lua-users home
lua-l archive

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


> True. But whether it is useful or not depends on usage, and _that_ is up
to
> the programmer. If the programmer wants to mimic a table (using
metamethods
> on tables or user data) then they will NEED a way to intercept both "next
()"
> and "lua_next()".

True enough. That is a weakness in the design, I think. However, lua_next()
currently does not work with anything other than vanilla tables, whereas
next() is interceptable (or redefinable). Sort of. (i.e. you have to
redefine it in two different globals tables if you want both C and Lua
functions to use the redefined value, and you are changing globals tables
in the app.)

In any event, given that there is not currently an API which can be used to
iterate an arbitrary object, it seems reasonable to think about how such a
beast might look. And my proposal would be to actually implement lua_pairs
(or perhaps lua_tuples :) which would call the __pairs metamethod to
construct an interator and a "state". In fact, a minor change in the
lua_next() definition could satisfy this without adding a new API, but I
don't think new APIs are that expensive, because the "nil" key argument
could trigger the call to __pairs. But this is not backwards-compatible.

The C-iteration would look something like this:

{
  int key_index;
  for (key_index = lua_start(L, table_index); lua_iterate(L, key_index,
n_args); ) {
      /* The key is now at key_index and the other iteration results follow
*/
  }
  lua_end(L, key_index);
      /* lua_starts must match lua_ends; it is necessary to restore the
stack */
}

The above functions can be written using the API, although they could also
become part of the API:

> If "__next" is too inefficent to implement for a particular table design
> then the programmer _might_  instead choose to intercept "pairs()".
However,
> since I don't think  there is a "lua_pairs()" function (though I might be
> wrong), one should be able to just reimplement "pairs()" as one wishes.

As indeed one can.

> That said, in common usage people may prefer to produce more general
> generator functions that run on internal state (especially when they do
not
> actually match table behaviour). It might be nice, therefore, if the
'for'
> statement could also support that format (ie, a single function closure
> which is repetively called until nil is returned). Eg:

<snip>

They can. It worked exactly as you wrote it, except you have to use
"io.write" instead of "write":

>   function roll_dice(n)
>>     local i = 0
>>     return
>>       function()
>>         if (i<n) then
>>           i = i +1
>>           return math.random(6)
>>         else
>>           return nil
>>         end
>>       end
>>   end
>
>   for v in roll_dice(5) do io.write('  '..v) end
  3  5  2  4  3>