# Sleepy Coder

Hoy. :-) I am Sleepy_Coder in #lua on Freenode. I frequently talk/blabber and stress everyone out with the little things I nitpick at.

Toodles ~

## Lua 5.3 Wishlist

### For Loops Should Allow Modification of Iterator State Variables

```-- Benefits of what I'm proposing:

-- No need for a 'continue' or 'skip' keyword if you can control the iterator from inside the loop body (it could even allow for break-like behavior)
-- With this it would be possible to skip several iterations of a loop, rather than just one-by-one if a skip or continue keyword were added

-- Problem

-- Lua's for loops don't let us modify the key and value (and whatever other identifier declared) passed
-- to the loop body when (on the next iteration) it uses these values for the next call of the iterator

for k, v in ipairs({ 1, 2, 3, 4, 5 }) do
print(k, v)

if k == 2 then k = k + 1 end -- we can't actually do this to "skip" the 3rd iteration, but I wish we could
end

-- ipairs({ 1, 2, 3, 4, 5 }) returns: iterator_function, { 1, 2, 3, 4, 5 }, 0, nil
-- 1st iteration: iterator_function({ 1, 2, 3, 4, 5 }, 0, nil) -- returns 1, 1
-- 2nd iteration: iterator_function({ 1, 2, 3, 4, 5 }, 1, 1)   -- returns 2, 2
-- 3rd iteration: etc...

-- What I Want:

for k, v, not_used1 in ipairs({ 1, 2, 3, 4, 5 }) do
print(k, v, not_used1)

-- we want to modify the first value passed to the next iteration
if k == 2 then k = k + 1 end
end

-- Translation:

ret = { ipairs({ 1, 2, 3, 4, 5 }) }

-- first 2 items from the generator (my_pairs()) would be the iterator and item it's iterating over
-- (some generators don't have items they iterate over and return nil as the 2nd arg)
iter, iter_self = unpack(ret)

-- remove iter and iter_self from beginning
ret = { unpack(ret, 3) } -- key value is at index 3

-- create our initial k, v, not_used1
k, v, not_used1 = unpack(ret)

-- the rule is that iterators stop
-- iterating when the k section is nil
while true do
-- the table is needed because the iterator could return multiple items
ret = { iter(iter_self, unpack(ret)) } -- our initial k, v, not_used1 are already in ret
-- ^ this should be easier done in C when you can work with the stack, no new table on each iteration

-- set our new key-value for inside the loop body
k, v, not_used1 = unpack(ret)

if k == nil then
break
end

-- example loop body from above
do
print(k, v, not_used1)

-- we can now modify the first 2 values returned of the iterator to control the loop behavior
if k == 2 then k = k + 1 end
end

-- these may have changed, reset ret
ret = { k, v, not_used1, unpack(ret, 4) } -- 4 is again, dependant on identifiers declared
end

-- ^ this works, but isn't nearly as pretty
-- it produces:
-- 1	1	nil
-- 2	2	nil
-- 4	4	nil
-- 5	5	nil

-- Considerations:

-- 1) you should be able to modify whatever stateful values the iterator passes to the body of the loop
-- 2) it should be noted that in order to interchangeably use generators, they must return at least 2 values on each successful iteration, some_table[k] = v is convention: for k, v pairs/ipairs({ 1, 2, 3 }) do some_table[k] = v end
-- 3) this way of writing the functional for loop should allow for iterators returning varargs
```

RecentChanges · preferences
edit · history
Last edited May 26, 2012 5:44 pm GMT (diff)