lua-users home
lua-l archive

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


On Wed, Jul 3, 2013 at 4:45 PM, Eike Decker <zet23t@googlemail.com> wrote:
> 2013/7/3 Coda Highland <chighland@gmail.com>:
>> On Wed, Jul 3, 2013 at 12:39 PM, Eike Decker <zet23t@googlemail.com> wrote:
>>>
>>> Am 03.07.2013 20:46 schrieb "Roberto Ierusalimschy"
>>> <roberto@inf.puc-rio.br>:
>>>>
>>>> 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
>>>
>>
>>
>> It's a brilliant idea, but is "nil" an alias for "nil(defined)" or
>> "nil(undefined)"? It'd have to be an alias for "nil(undefined)" to
>> avoid breaking "t[#t] = nil" and similar idioms.
>>
>> /s/ Adam
>
> If you write "nil", you specify it, so it's nil(defined). The
> undefined nil value is only created when it originated from a lack of
> specification.
> Actually, deletion could work this way:
>
> t[#t] = jfdosaifjosaifjos
>
> ... as long as the environment table / upvalue lookup for that value
> is not defined ;).
> So you could also do this:
>
> local del
> t[#t] = undefined
> t[#t] = del
>
> ... whatever you use, as long as your source is an undefined nil
> value, the table value gets deleted. Creating an undefined nil value
> is simple - just don't initialize the local variable and you have it
> :)
>
> Eike
>

Eike,

Upon reflection (personal, not the CS kind), I observe that this
solution does not solve many use cases that it otherwise might.

local foo

if this is "nil(undefined)" as in your proposal, it might be described
as a sort of sub-type of nil.

However if `baz` is nowhere in my program and I call `has(baz)` it
reports the exact same status as `foo`.

Instead, I maintain that your approach for description of undefined vs
defined nils is sound, I would maintain in all three cases of `foo`,
the variables are all `nil(defined)`:

local  foo

local foo = nil

f = function(foo)

end


That is because in all three cases, `foo` blocks access to any prior
scope's foo. They play a role in the environment and there for are
fundamentally different than if they were never defined, at all. And
so, we're sort of back to "empty", which isn't necessarily bad. To me,
it feels like adding a great feature instead of completing a part of
the language that some may argue is sort of... missing, and as a
result arriving at the same capability.

I don't suggest that `local foo` resolving to `nil(undefined)" (or
making `type` spit out `nil, undefined`) will not work for many use
cases, including the OPs.

I would only suggest that it's better to add a `delete` facility, then
to change the behavior of assigning something to nothing, which has a
different behavior than if the thing never existed. There are times
where it'd be helpful to know if `foo` was really and truly there, or
not.

[delete would create a need to be able to protect a variable from
deleting. Otherwise _ENV = nil could be wiped out with delete(_ENV)]

-Andrew