lua-users home
lua-l archive

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


I suggested __type() as an extension to type() some time ago, for other reasons. In fact, it's an odd omission (to my mind), given that we have __tostring() and others. This appeared to have little support, so I went ahead and created my own version for my current project.

As far as empty/null/nil/array holes is concerned. My root cause analysis comes down to the fact that nil is subtly overloaded. The language succeeds in hiding this overloading in all but one place: when an array element is assigned nil. At that point the overloading becomes apparent; nil means both "no value" and "delete", one a noun, one a verb. In EVERY other part of the language, this distinction can be ignored because the two are made equivalent by the language design: viewing a table as having an infinite number of elements, most of which are nils; the same for function arguments and return values etc.

In arrays, however, this hiding breaks down, because "no value" and "delete" cannot be split apart; I cannot use nil *inside* an array. All the suggestions so far (including my own "empty" value) come down to being able to split apart the idea of the "size" of an array from the presence of an "empty" element (however you define empty).

So how DO you define "empty" (assuming there is case for it at all)? Roberto suggested "false", but in my particular case i'm already using booleans within the table. And numbers, and strings etc. So my solution was to create a unique "empty" value using light userdata, which was all I needed. This worked better for me than special array properties (table.has() etc), as I could also pass "empty" as a function argument/return value. The empty table trick works within a given Lua state, but, again, I wanted to be able to tunnel empty values between Lua states, where each would NOT share the same empty table (whereas they CAN share the same distinguished light userdata).

I also want to address a possible confusion about names: I used the word "empty" to mean a distinguished value that had no special properties other than it was different from all other values; this was my approach to solving the "empty" problem (good or bad though it might be). However, I realize some posters have assumed by "empty" I meant a property of a table element (which is one way to address this, of course). In my head, "empty" would evaluate as "true" in a boolean context for example, so in reality "empty" is not a good name; to my mind "empty" is more like NaN.

So to my mind this long discussion comes down to three questions:
1. Is there a need for an "empty" element within an array (where "empty" as a concept is tbd)?
2. Assuming #1 is "yes", would this be useful as a standardized technique so that everyone uses the same convention?
3. Assuming #2 is "yes", what form should this standard technique take?

My apologies for the long post, I just wanted to clarify a few things in my head.

--Tim






On Jul 5, 2013, at 11:40 AM, Andrew Starks <andrew.starks@trms.com> wrote:



On Friday, July 5, 2013, Mark Hamburg wrote:
Fixing the "problem" with an ax. Just come out and say that Lua doesn't have arrays. Get rid of ipairs. Get rid of #. Get rid of table.insert, etc.

If you want to iterate an array-like table use:

    for i = 1, n do
        local v = t[ i ]
        -- process entry i with value v
    end

It's your problem to figure out n.

This solution is, of course, trivial to implement. Arguably, you have it today since it just avoids use  or some features.

But it is also a pain. How do we find n above? One answer is maxn. If we are going to iterate the whole array, this doesn't make the time complexity any worse.

What this won't handle and is where the generic encoding solutions may run into trouble is not holes in the middle but holes at the end.

To resolve that, we can introduce a magic value and then bring # and ipairs back provided that one understands the need to either not have holes or to use the magic value to have them work "correctly".

Or we can introduce an array module that gives us a structure with the desired semantics.

The latter seems cleaner. I would probably resist bringing back ipairs on the basis that it is only sensible for arrays and hence should be array.ipairs. The argument for the length operator is probably one of efficiency of execution and notation, but I'm not fully sold on it. (They can come back/stay but they would probably exist under a compatibility switch.)

Simple but also arguably dramatic in a way that isn't necessarily warranted.

Finally, one addition in support of any of these answers that might be good is a __type fast metatable field that type would check with rawtype taking over type’s current role. That way, one could check to see whether something was really an array as opposed to just a table (or a userdata depending n implementation).

Mark



Personally, after reading this and Jay's post...

You guy's are right. Lua is fine. My passion has subsided and reason is back in control. :)

FWIW: Monkey patching `type` so that it outputs:

[base_type], [the string value at metafield "__type" or the return value from function call at "__type"] 

...is something that I do all of the time. It was the basis for my earlier suggestion. 

It works pretty well for me and the fact that I have to patch it to do it that way is also fine. It just means that I also need to adapt other libraries that do similar things (Penlight) to the same convention. That's just kind of "how it is in Lua."

-- Andrew