lua-users home
lua-l archive

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


2009/7/28 Cosmin Apreutesei <cosmin.apreutesei@gazolin.ro>:
>>> - why is there a difference between a list of nil arguments and no
>>> argument? --> nil is acting like any other value here.
>>
>> That's an extra feature provided for convenience. Just like you can
>> see tables as infinite key-value pairs, you can see argument list as
>> infinite list of values, defaulting to nil. As a convenience you can
>> get the number of values that was actually passed to a function call,
>> but you can still access all elements of the argument list (just call
>> select(42, ...) for example).
>
> Yea, but providing the arg. count is leaking the abstraction. If I am
> to make an optional parameter in the middle of the arg. list, should I
> account for the real arg. count or use an ipairs()-like iteration? In
> other words, should I account for trailing nils? What if some other
> function that my function wraps up is sensible about the arg. count as
> well? I have to carry around arg. count everywhere. Whereas without
> this leak, {...} would had been enough.

Vararg lists are special kind of objects that you cannot instantiate
or reference. They are not tables.

You don't have to use or allow the vararg feature of Lua. You can
write functions that expect a fixed number of arguments, no more and
no less (even with forced trailing nils).

>> nil is a normal value, just like 42, true, false and "Hello World!".
>> The authors decided that the value associated to nil in a table should
>> always be nil, that key-value pair is read-only. Sometimes you have to
>> accept exceptions to the rule. That exception has motivations
>> (previously discussed on that list).
>
> I dig it. But then __index should not be called for the nil key to
> make sure the rule is not broken.

We're talking about an exception, why should it obey another rule ?
Also the read-only nil-key pair is a feature of tables, while index
and newindex let you build other types of objects (eventually with
different semantics) on top of tables. Keep in mind that index and
newindex in tables are exceptions in the real of metamethods, because
they let you override a behaviour that is otherwise perfectly defined
and valid.

>> It simplifies the iterator protocol a lot to mark the end of iteration
>> with a special value rather than another mechanism. Whatever the
>> special value (currently it's nil), if it's a regular value, it
>> implies you cannot iterate over it. As with most questions of this
>> thread it's mostly a matter of taste.
>
> This I don't buy. How does it simplifies it? The few iterators that I
> wrote don't get any more complex if they return a flag up front. I
> don't think it's a matter of taste when the result is loss of
> functionality (i.e. it's not natural to have a pseudo-index for
> iterators like varargs(...), or sparse_array:values()).

Actually, all you're asking for is to hide the first variable of a for
loop. Because nothing prevent you from using your proposed iterators
with the current for loop. The only real difference is that the flag
variable is not hidden. I can't count how often I skip the first
variable of a pairs loop:

for _,value in pairs(t) do process(value) end

The _ variable is a very common way to "skip" an unneeded value.

Also a side effect of the current iterator protocol is that it plays
nicely with table indexing. For example in
   local t = {}
   for x in values(...) do t[x] = true end
you are sure that the loop content will not throw an error (of course
the iterator itself can). That's not a crucial feature, but that's one
nonetheless.

>> The array is not such a fundamental data structure in Lua, as opposed
>> to C for example. I think all these pseudo-problems around them
>> quickly vanish once you start programming in Lua "à la Lua".
>
> I'm getting there :)
>
> But (I'm not letting this go you see) if I write a function that
> supposedly works with the "array part" of a table, and not just with
> an "array", then I must be careful not to use #t and only use ipairs()
> instead. Or maybe I shouldn't care and always ask for a proper array?

When I talked about "à la Lua" programming, I meant that in Lua you
have much more powerful data structures than in C. With a simple pair
of curly braces, you can have maps, sets, arbitrary complex object
structures, without the hassle to predeclare that structure. So cases
where you really need an array are very few. And for these cases, you
should ask yourself what defines an array in that precise situation.
Of course you have the basic "i in ipairs(t)" vs. "i=1,#t". But also
should your function taking an array ignore the hash part of the table
? Should it throw an error ? Should it copy it in the output array if
any ?