lua-users home
lua-l archive

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



Am 04.07.2013 01:24 schrieb "Andrew Starks" <andrew.starks@trms.com>:
>
> 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.

Hello Andrew,

No, this is not the case. It is a regular lexical value lookup, thus:

  local foo
  print(defined(foo)) -- false

  do
    local foo = nil
    print(defined(foo)) -- true
  end
  print(defined(foo) -- false

  _G.foo = nil
  print(defined(_G.foo)) -- true

  function f(foo) 
    print(defined(foo))
  end
  f() -- false
  f(nil) -- true
  f(foo) -- false

The introduction of a dual-nil value that look the same and are equally handled and compared is not changing anything in Lua and as long table deletion works the same (meaning any nil assignment deletes an entry), this approach is 100% compatible. 

But it lets you figure out if a value was actively passed or not. Of course, an undefined nil can come around such as:

  function f(x) print(defined(x)) end
  function g(y) f(y) end
  g(nil) -- true
  g() -- false - despite being passed to f. It behaves as if 'f' was called without arguments


I hope this is clarifying what I mean. In general, this approach introduces an additional meaning of nil that is compatible with Tim's initial "empty value" request without affecting compatibility with plain Lua and without adding a entire new value. It is a mere extension of nil.

Of course I am ignorant of the implementation side here :)

Eike