lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Here's a rewrite based on the manual's definition of the generic for (a better approach):

A for statement like

     for var_1, ···, var_n in explist do block end

is equivalent to the code:

     do
       local f, s, var = explist

       --proposed addition
       if type(f)~= "function" then
         local meta_f = metatable(f).__iter
         if not meta_f and type(f)=="table" then meta_f = next
         if meta_f then f, s, var = meta_f, f, s end
       end

       while true do
         local var_1, ···, var_n = f(s, var)
         var = var_1
         if var == nil then break end
         block
       end
     end

Hopefully that makes sense.

On Mon, 24 May 2010 15:52:29 -0700, Stuart P. Bentley <stuart@testtrack4.com> wrote:

There were some posts a few days ago that were nested several deep in a discussion on ipairs [1], in which the idea was brought up of using a different approach to metamethods for the generic for than the current working proposal of __pairs and __ipairs. I felt that the idea should be brought to the forefront, so I've written up a more formal "proposal".

The way I'd conceptualized it was that, when the generic-for encountered an iterator that wasn't a function, before raising an error, it would first check the metatable for a function at the "__iter" index. If it found a function there, it would use it, allowing users to override the iterative behavior over an object more simply than overriding its functionality when passed to pairs() (or ipairs, even though the manual suggests it should be deprecated).

Additionally, you could use this to bring back the "for k,v in t do" syntax by making the default function for tables be next() in the event they don't have an __iter metamethod.

To put the original concept in terms of the Lua manual's definitions for metamethods:

function generic_for_iterate (iter, ...)
if ... then -- if the iteration has not completed (iterator hasn't returned nil)
     if type(iter) == "function" then -- got iterator?
return generic_for_iterate(iter,iter(...)) --continue iterating with it
     else -- got some
       meta_iter = metatable(iter).__iter
       if meta_iter then -- metatable has iterator?
return generic_for_iterate(meta_iter,meta_iter(iter)) -- start iterating with metatable's iterator
       elseif type(iter) == "table" then -- default case for tables
return generic_for_iterate(next,next(iter)) -- start iterating with the default iterator
       else --no iterator available: default behavior
error("this was an ellipsis in the original manual but I couldn't copy it correctly")
       end
     end
   end
end

Note that I'm not the king of generic for iteration, and if this appears to change the semantics of generic for iterators, that is unintentional. The goal was to show the logic flow for selecting an iterator with metamethods. (It also assumes generic_for_iterate only proceeds after the code inside the loop has been evaluated, of course.)

[1] http://lua-users.org/lists/lua-l/2010-05/msg00581.html