Sleepy Coder

lua-users home
wiki

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)