lua-users home
lua-l archive

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

On Wed, Jul 3, 2013 at 2:39 PM, Eike Decker <> wrote:
> Am 03.07.2013 20:46 schrieb "Roberto Ierusalimschy"
> <>:
>> If we add a new value in Lua (call it null, empty, nothing, whatever)
>> to represent null in JSON, the problem with JSON is solved, because
>> we do not change JSON. This change is trivial to do, but only solves
>> the JSON problem.
>> If we add a new value in Lua (call it null, empty, nothing, whatever)
>> to represent null in *Lua*, the problem is not solved. Now Lua has a new
>> value, and therefore we need yet another value to represent this new
>> Lua value. Adding new values will not solve the problem in Lua. Period.
>> -- Roberto
> Just an unfinished premature loud thought: what if nil is a type with
> different states similar to Boolean that can be true or false? Maybe this is
> a very stupid idea but I want to elaborate on it a bit...
> Setup:
> The states could be nil(defined)/nil(undefined). Both values are very
> special:
> nil(defined) == nil(undefined) -- yes, this results in "true"
> a,b = nil -- a is nil(defined), b is nil(undefined)
> Actually, both nil states are indistinguishable on a syntax level - the
> distinguishing can only happen through a special function that can tell the
> difference, nothing else can. This somewhat similar to the SQL concept where
> null is checked by doing "is null" and not "= null", which is false (if I
> recall correctly).
> Consequences:
> I think the result of this logic could be disastrous.... But maybe this
> crazy logic still makes sense:
>   a,b = nil
>   function f(a,b,c)
>     -- if called this way: f(a,b), a is nil(defined), b and c are
> nil(undefined)
>     -- if called this way: f(a,b or nil), a and b are nil(defined), c is
> nil(undefined)
>   end
> Interesting is also the case for tables: if a value is nil(defined), it
> continues to be present in the table and the slot is NOT removed. Thus:
>   function delete() end -- returns nil(undefined)
>   t = { a=1, b=nil, c=delete()}
>   t.a = delete()
>   -- status: t.b is nil(defined), t.a and t.c are nil(undefined) and thus do
> not exist
> Consequently, popping an array element works by doing "t[#t] = delete()" or
> "_,t[#t] = nil"  - which is interestingly quite close to my last suggestion
> of storing nil values in tables. Also interesting is, that arrays remain
> arrays as long defined nil values are present and forming a sequence. Also,
> it can be distinguished between functions that return a value or no value -
> or if the number of returned values is invalid (somehow, this is where
> debugging becomes interesting).
> The concept is maybe very wacky, but somehow, it's intriguing me ... What I
> strongly dislike is, that it's difficult to explain to beginners and also
> hard to understand maybe. On the contrary, the current nil concept and the
> deletion of array elements is also lacking.
> From my point of view, this would be almost completely compatible with
> existing code, except that table element deletion needs to be revisited (we
> had this discussion in the other thread).
> Well, as crazy as this idea might be, I hope have given you something
> interesting/fun to think on :)
> Cheers,
> Eike


I think it is important to distinguish between assignment and deleting:

t.a = delete()

Assigning delete seems to imply that there is a value here. In this
case, would the definition of delete be

function delete() return end

If so, then shouldn't

t.a =

suffice? That seems... wrong. But also, it solves a bunch of problems,
doesn't it?

To my thinking, deleting is something that you do to an existing
variable, not something that you assign to it:

table.delete(t, "a")

says, "here is a table, please delete the value/reference at this
index and do the same to its key."[1]

As for the behavior of tables, especially related to popping values...
I see your point. Previously, I was imagining default behavior for
`__index` and `__newindex` but that won't work, I don't think.

I think , to use another's analogy, this is the tasteless egg that is
breaking. I don't see anyway around changing the way that `t[#t] =
nil` behaves, which is most significant when it's related to ipairs
and len.

Approach #1: Introduce another iterator, which looked at empty values
instead of nil values. This would bring it back to the array library

for i, v in array(t) do
This doesn't solve the issue for len, however. Perhaps one would need
to redefine __len to check stop at the first table.exists(t, i), if
that behavior was required?

Approach #2: another metamevent (the refuge of the damned) `__setindexnil`.

Default is:

__setindexnil = function(t, i)
    if tonumber(i) then
        if  i < #t then
            rawset(t, i, nil)

... and ipairs and len work on hole-laden indexed arrays by looking
for the first undefined key. t[#t] = nil would delete the last key.

Seems like another iterator would be less disruptive. It also seems
that `ipairs` should just work on arrays with nil values, given the
ability detect undefined keys.


[1] [An extension, or perhaps a more complete implementation, would
include something along the lines of `delete(t)`, which would delete
the table. If one can delete variables, then I also suggest that there
be a limitation that says, "You can only delete within the local
scope. `table.delete` may be used to delete the indexes of any
accessible table, regardless of scope."]