I noticed that the 5.5 release is on the horizon and that for
loop variables become constant.
I personally liked being able to change a loop variable for a
current iteration. It was useful sometimes for patching up broken
values in an iteration from within a nested block:
for k, v in pairs(t) do
local k = k -- must be added for 5.5.0-beta
if type(k) == 'string' and k:find "^_" then k = k:match "[^_]+" end
print(k, v)
end
In this case a simple match with an inline check would have
sufficed, which would not necessarily need loop variables being
mutable (you could just write local k = <cond>
and <fix> or k). Fixing a loop
value from within a nested block is sometimes however quite handy.
Now with loop values being constant, this quick fix needs an extra
line at the top of the loop to work for 5.5.0-beta. So scripts
abusing the implementation specific behavior of overwriting loop
variables will break with 5.5:
for k, v in pairs(t) do
local k = k -- must be added for 5.5.0-beta
if type(k) == 'string' and k:find "^_" then k = k:match
"[^_]+" end
print(k, v)
end
The manual is quite clear that changing a loop variable should be avoided. All implementations I encountered so far however handle them as kind of implicit local variables to the current iteration and changing them has no effect on the iteration process itself, which makes it kind of an implicit feature.
So what's the rationale to make them constant now? Does it have
performance reasons? It feels a little unnecessary to break
existing scripts which rely on this implementation detail.
May I suggest if Lua is changing the semantics of loop variables and thus breaking some scripts, then maybe it should instead open up the possibilities, rather than closing them down? i.e. I found the interesting proposal of enabling forward jumps in numerical for loops, by Martin Eden:
for i = 1, #s do
local c = s:sub(i, i)
if (c == [[\]]) then
i = i + 1
c = s:sub(i, i)
end
io.write(c)
end
Whenever I had to do something similar, I was forced to
use a while loop instead. For generic loops using pairs this
doesn't make a lot of sense, due to the randomization of the
next key-value-pair. ipairs however could benefit
from the change of skipping values within an iteration.
If the new minor update breaks an implementation feature, I personally would like to get something new instead of simply removing what worked before.
P.S. While we are talking about for loops, why is this not a thing?
local function range(n) return 1, n end local function reverse(n) return n, 1, -1 end for i = range(8) do --[[ going from 1..8 ascending ]] end for j = reverse(8) do --[[ going from 8..1 descending ]] end
But as I understand it, a slightly nerving pecularity of Lua for loop
variables is, that they may NOT be modified to "speed up" the loop, or
to break a loop earlier, or for other purposes (in C / Java / Basic
this works, and I think most programmers expect this to work in a for
loop).
Yes and that's exactly my point: The quirk of Lua became a
feature for me. Fixing the iteration variable for a single
iteration rather than influencing the whole iteration process is
useful at times if you quickly want to fix a value from within a
nested block. Granted you can fix it in a nesting block after
declaring a local k, v = k, v at the top of the loop,
but this will break existing scripts relying on the behavior after
the release.
If it is being used, why change it?