lua-users home
lua-l archive

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




On Thursday, July 4, 2013, Eike Decker wrote:

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

I understood your idea to be as you've illustrated, but this was illuminating in that it highlighted an important use case that I had not appreciated and which would not be covered as easily by my (at this time) preference: "Did they set the value or not?"

In my scenario, in order to know that, you'd either a) need to use vararg or b) horribly break Lua. 

I believe that the meaningful difference between is that you are solving the following question:

Was a variable, which may or may not exist,  set explicitly to `nil` or wasn't it?

As opposed to my approach, which answers:

Does this name exist as a variable, at all. 

The salient difference being that in my case, if no, then global presence of the variable would be in scope, if it were later introduced (say in a resumed coroutine) and in your case it may or may not be.

To illustrate:
local exists = exists
local print= print ; print("hi!") --> "hi!"
do
  _ENV = {foo = nil}
local print

-- begin what my proposal would more or less mean

exists(print)
--> true
type(print) 
--> nil, defined
delete(print)
--> true, function #0023AC0 
   -- perhaps. Not sure what delete should return...
   -- Success or failure plus the value of the deleted variable seems prudent.  

exists(print)
--> true
type(print)
--> function
delete(print)
--> nil, Attempt to delete undefined local 'print'.
delete(_ENV)
--> nil, Attempt to delete undefined local '_ENV'.
delete(foo)
-->nil, Attempt to delete undefined local 'foo'.
exists(_ENV.foo) 
--> true
exists(foo)
--> true
exists(_ENV.baz)
--> false
delete(_ENV, foo)
--> true, nil
exists(foo)
-->false
end
----
I believe that how your example would behave is self evident, except maybe I'm not sure what would `delete(print)` do, inside the given block... I assume it would reset the local print variable to "nil (undefined)", no?

I see the merit in your approach and would prefer it over the status quo. More generally, you can know if someone explicitly set something to `nil`.

I wonder if you also see the merit of knowing whether or not a variable really exists and also being able to delete local variables / table keys? Or, is there no upside to what I'm trying to get at? Does my approach make the OP's use case difficult?

(Deleting locals isn't a necessary feature and is somewhat orthogonal to the larger goal)


-Andrew