lua-users home
lua-l archive

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


RLake:
> My original thought was a __next metamethod. But after I tried writing a
> few of them, I decided that __pairs is actually a lot easier to implement
> in many interesting cases. Try a few and see for yourself...

> That is a general problem with iterations which require retained state.
> The only state a __next metamethod would have is the key itself, and it is
> undesirable to overload the key with internal state information because it
> is exposed to user code (and also it is quite useful that it be a key, and
> not a state description.)

It is true that, with the new lexical scoping, it becomes easy to create
single-function iterators (that's how I do streams in my Lua Parser in Lua
project). The authors *might* have chosen to do 'for' that way (which might
have been quite efficient with an internal pointer into the hash table) but
they have chosen, for whatever reason, to instead to use the functionality
of the standard 'next' function to implement 'for'.

So, honouring that, I agree that a __next metamethod would only get the
*key* (not some internal state) to deal with. This may not be as efficient
but (since we are simulating a table here... which is in essence just
key:value pairs) it will always be possible.

An example (in the basic line of the one given by Wim Couwenberg, but
without the extra 'state' stuff which I'm not sure why it's there) is:

  -- tnext() : designed as __next for tables that have an __index Table.
  local function tnext(t,oi)
    repeat
      -- Return the next index:value if it exists in the table...
      local i,v = next(t,oi)
      if i then return i,v end
      -- ... otherwise go down another level of indirection.
      local m = getmetatable(t)
      t = m and m.__index
      assert(t and (type(t) ~= "table"),"__index must a table or nil!")
    until (t == nil)
    return nil,nil
  end

  -- Test data.
  T = {a=1, b=2, c=3}
  setmetatable(T, {__index = {d=4, e=5}, __next=tnext})

  -- Run test.
  for i,v = pairs(T) do
    print(i,v)
  end


Wim Couwenberg:
(snip Wim's version)
> Note that this only works if __index is an actual table, not a function.
> If something similar must work for __index functions as well, then I think
> we really _do_ need an additional __next metafunction that enumerates all
> key/value pairs that can be accessed through this function.

If __index is a function (which simulates a table lookup) then we are going
to need __next to be designed to match it (by simulating a scan of the same
pseudo-table). If someone has a sample __index function I'll try to come up
with an example matching __next.


*cheers*
Peter Hill.