• Subject: [NoW] About numeric for-loop
• From: Egor Skriptunoff <egor.skriptunoff@...>
• Date: Thu, 17 Jan 2019 00:45:10 +0300

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

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;

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.

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
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)