lua-users home
lua-l archive

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


Am 01.08.2014 14:00 schröbte Jean-Luc Jumpertz:

Le 1 août 2014 à 13:07, Philipp Janda <siffiejoe@gmx.net> a écrit :

Am 01.08.2014 11:49 schröbte Jean-Luc Jumpertz:
2) IMO the new behavior of ipairs is simple and consistent (even if different of the 5.2 behavior in a few corner cases).

The new `ipairs` stops at the first nil value for normal tables, and at `#t` for tables with `__len` or `__index`. So it's already twice as complex as the obvious alternative: stop at the first nil value, period. Works better for something like linked lists, too, where calculating the length is expensive ...

Correct me if I'm wrong, but
- for plain tables without '__len' nor '__index'  metamethod, the performance cost and behavior are exactly the same as in 5.2 (function ipairsaux_raw);

I agree.

- defining a '__len' metamethod allows to execute a for loop on a table with holes in it (which I consider as a real progress!)

So does `__ipairs`, but I don't necessarily consider this progress. One nice thing about `ipairs` was that it would never yield a nil value. But I guess even with `__ipairs` one has to check anyway ...

- so the only case where there actually is a performance penalty is on a table with __index defined and not __len. I wonder if there a many examples of this case...

This case can be handled by the plain table version as well (raw accesses and no `luaL_len` calls), because: The length operator (or the C API equivalent) is only defined for sequences. Sequences do not contain nils, so the `__index` metamethod will never be called. Using the plain table version will even be well-defined for the non-sequence case: it will stop at the first hole.

So:
1.) less code
2.) better performance in one case
3.) one less undefined case

I'd call that win-win-win.

I still hope that the behavior is changed to "stop at the first nil", and that the old `__ipairs` metamethod is kept around for those cases where this isn't enough (e.g. I have implemented `__ipairs` for my multikey module[1], and computing a length would be rather complicated).


And btw testing the  '__len' and '__index'  metamethods in function 'luaB_ipairs' has an almost null performance cost and gives you additional flexibility, so what would it bring to restrict this test to the '__len' metamethod, as Philipp Janda proposed? :-)

It's useless code that causes one extra case of undefined behavior, so why keep it? And what's the additional flexibility?

The additional flexibility is to allow you to freely define the values you want to return for table[i] and to keep it consistent between direct accesses like << a = my_table[i] >> and for loops like << for i, v in ipairs(my_table) >>, even if you don't redefine __len

As I argue above, you can't. `__index` without `__len` is either superfluous ( `__index` never gets called) or highly unpredictable (undefined behavior, could stop in mid-loop in current Lua implementation).


The performance cost I mentioned comes from the repeated calls to `luaL_len` and has nothing to do with the metamethods you check for.
Sure. I wasn't arguing on that. :-)

Jean-Luc


Philipp

[1]: https://github.com/siffiejoe/lua-multikey/blob/master/src/multikey.lua#L192