lua-users home
lua-l archive

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


On 2013-06-27 8:57 PM, "Tim Hill" <drtimhill@gmail.com> wrote:
>
> I'm going to get shot for suggesting this… (hides under bed)
>
> I've been writing a lot of Lua code recently, some of it quite generic in nature. One thing I frequently come up against is the need to handle data polymorphically in tables. And an effect of this is to hit against the overloaded use of "nil" in Lua.
>
> It seems to me that "nil" is overloaded; it means both a noun: "no value" and a verb: "delete this table entry". Now, most of the time, the delete is hidden since reading a non-existent table entry returns nil. So having an explicitly stored nil versus having no value stored at all is equivalent (all this I love, btw … 100 points to Lua).
>
> But it all rather breaks down with arrays (sequences). I cannot have sparse arrays, which in Lua terms means I cannot have "nil" in an array element. So, when writing polymorphic code, how do I handle cases (which, trust me, i DO have to handle, with "no value" in an array element? There are, of course, a whole bunch of work-arounds: Use a sentinel value; use an empty table (assuming empty tables aren't value data, and ignoring that each one is unique); use a magic userdata (assuming I have access to C code to make one); etc etc.
>
> But, let's face it; they ARE all workarounds. I think there IS a case to be made for being able to store a value in a Lua array that is uniquely NOT any other Lua value. Essentially, I think that value is "empty"; a valid Lua value that is simply not the same as any other Lua value (including nil).
>
> Basically, empty would act like nil in most regards, except:
> -- Storing empty in a table element actually stores the value, rather than deletes it.
> -- When used in a boolean context, the empty value evaluates to true (unlike nil).
> -- Has a type() of "empty"
>
> Other arguments in favor of this:
> -- Judging by the mail list chatter, a lot of Lua beginners struggle with the problem of nil in sequences.
>
> -- Better impedance matching to SQL NULL values; since empty can bridge to a SQL NULL when a Lua array is used to hold a SQL row.
>
> Thoughts anyone?
> --Tim
>
>

I'm not really sure what the difference would be between storing a sentinel table reference and storing "empty". It actually occupies the table entry and it evaluates to true, so it meets the first two differences you mentioned. With some metatable magic you could give it a type of "empty" too if you really wanted.

The fact that empty tables are unique helps with this method, because you can define an "empty" variable and use it just as you would if it were a special, built-in value (like nil), while not affecting the ability to store other, unrelated empty tables (e.g. a list that just happens to be empty at the moment). You just need to take care not to modify it or shadow it.

The one significant advantage I can see is that a database wrapper can automatically convert this magic value to and from null. Of course this can still be done if "empty" is an ordinary variable rather than a keyword; it's just a little more difficult because you need to make sure the database module is using the same "empty" as the rest of the code.

I can see how it'd be helpful if the standard Lua libraries defined a global "empty" variable to help ensure every module is using the same value, and if you're paranoid (or debugging, perhaps) it could even use a metatable on _G to prevent that variable being modified (although that wouldn't prevent a "local empty = {}" from causing trouble), but I don't think a whole new type is needed.