What's the rationale behind making for loop variables constant in 5.5?

199 views
Skip to first unread message

Sewbacca

unread,
Jul 6, 2025, 7:58:54 PMJul 6
to lu...@googlegroups.com

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

bil til

unread,
Jul 7, 2025, 6:13:10 AMJul 7
to lu...@googlegroups.com
Am Mo., 7. Juli 2025 um 01:58 Uhr schrieb 'Sewbacca' via lua-l
<lu...@googlegroups.com>:
>
> I noticed that the 5.5 release is on the horizon and that for loop variables become constant.

Sorry, that I did not read your long post completely.

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

E. g. your loop example with the "for i= 1, #s do..." would be such an example.

But this works NOT in Lua unfortunately (this is warned also in the
ref manual)... therefore now these loop variables are defined
constant... .

Gé Weijers

unread,
Jul 7, 2025, 9:02:45 AMJul 7
to lu...@googlegroups.com
On Mon, Jul 7, 2025 at 3:13 AM bil til <bilt...@gmail.com> wrote:

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


"most programmer expect this to work" That's probably only true because most new programmers only get exposed to C, C++, C# and Java these days.
The 'for' loop in C/Java is basically mostly syntactic sugar, it's not a true numeric for loop. Try converting this working Lua code to C:

for i = math.maxinteger - 3, math.maxinteger do
  print(i)
end

It's not trivial, and this does not work:

#include <inttypes.h>

for (intmax_t i = INTMAX_MAX-3; i <= INTMAX_MAX; i++)
   printf("%jd\n", i);

This will loop forever, because i <= INTMAX_MAX is always true. You can't break out of this loop by setting 'i' to another value because of that. 

Changing undefined behavior to invalid code is a good thing in my book.

--

Roberto Ierusalimschy

unread,
Jul 7, 2025, 2:21:44 PMJul 7
to 'Sewbacca' via lua-l
> So what's the rationale to make them constant now? Does it have performance
> reasons?

Yes. The old code does an implicit "local x = x" for all loops, in case
you modify 'x'. With the new semantics, the code only does it when you
ask for it.

-- Roberto

Sewbacca

unread,
Jul 8, 2025, 2:45:04 PMJul 8
to lu...@googlegroups.com

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?

Reply all
Reply to author
Forward
0 new messages