lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


"NoW" means "Nitpicking on Wednesdays"
(unimportant questions about Lua design and implementation)

Let's start with two simple examples:
   for x = -2^53, -2^53 do print(x) end
   for x = 1e100, 1e100 do print(x) end
Did you expect such results?

There is a problem in numeric "for"-loop: Lua internally exceeds the range of values specified by user.
 
The loop
   for x = a, b, c do ... end
is currently executed as follows:
   y = a - c
   while true do
      y = y + c
      if y <?= b then
         set x = y and execute the loop body
      else
         break
      end
   end
 
The range specified by user is: a <= x <= b
Lua exceeds it in the beginning (first value of y = a-c)
and in the end (the last value of y might be b+c).
It might happen that a-c+c ~= a
It might also happen that b+c == b
User intuitively implies the correctness of addition and comparison operators for values inside the range a <= x <= b
He might not expect that Lua performs calculations beyond this range.
 
Another not-a-good-thing is that Lua uses subtraction in numeric "for"-loop (the loop is supposed to always add and never subtract).
This would prevent generalization of numeric "for"-loop (Sony L. some time ago asked for this useful feature).
Addition and comparison metamethods should be enough to perform generalized numeric "for"-loop with arbitrary user objects.
Such objects must implement operations "obj+obj", "obj==obj", "obj<obj" and "obj<0".
The last one is needed to determine whether the loop is "increasing" (step>0) or "decreasing" (step<0).
 
 
My suggestion is to implement numeric "for"-loop in more accurate way:
- don't use subtraction;
- don't make addition when upper limit is already reached.
 
 
The loop
   for x = a, b, c do ... end
should be executed as follows:
   y = a
   while y <? b do
      set x = y and execute the loop body
      y = y + c
   end
   if y == b then
      set x = y and execute the loop body
   end
 
Lua VM instructions would be the following:
 
[1] FORPREP
[2] loop body
[3] FORLOOP
[4] next instruction after the loop
 
R(A)   = index
R(A+1) = limit
R(A+2) = step
R(A+3) = user loop variable
 

R(A), R(A+1) and R(A+2) might contain user objects instead of Lua numbers.
Operator ">?=" implies comparison of R(A+2) with number 0 to be resolved:
to ">=" for increasing loop, to "<=" for decreasing loop.
 
A trick is used here:
when the index R(A) reaches the limit R(A+1), the step R(A+2) is set to nil to mark the current iteration as final.
No addition is made after the final iteration.
 
function FORPREP(A, sBx)
   if R(A) >?= R(A+1) then
      if R(A) == R(A+1) then
         R(A+2) = nil   -- set step to nil (the next iteration will be final)
      else
         pc+=sBx  -- jump to [4]
         return
      end
   end
   R(A+3)=R(A)
end
 
function FORLOOP(A, sBx)
   if R(A+2) then  -- if step is not nil (if not after the final iteration) 
      R(A)+=R(A+2)
      if R(A) >?= R(A+1) then
         if R(A) == R(A+1) then
            R(A+2) = nil  -- set step to nil (the next iteration will be final)
         else
            return
         end
      end
      R(A+3)=R(A)
      pc+=sBx  -- jump to [2]
   end
end
 
This would involve unnoticeable decrease of performance of usual numeric "for"-loops.