lua-users home
lua-l archive

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


  In the 5th century BC Hippasus is said to have been killed by
Pythagoras, because he insisted on the fact that rational numbers do
not cover everything like sqrt(2). This is an urban lebend, sometimes
used as reference to hope to not get the same kind of response as 2500
years ago when suggesting something against the "doctrine". I won't
discuss irrational numbers but the virtue of letting go of nil. You do
not have to be convinced nor do I expect Luiz and Roberto to change
Lua. If it can be managed to be patched to the lua core it will be a
dialect. For now its just an idea I'd rather have written down once,
than letting it go to the drain immediatly.

Nil is not a first class value. It has a recurring scheme of cases
where it has a strange kind of double-meaning, nil as variable not
there, and nil as a result of something not-being there stored in a
variable, now not there. Same with recent discussions what to do if
inserting nil into a list. Or people requesting how to differ if a
function was called without a parameter or with nil as parameter. This
can be achieved in lua with select('#', ...) and only highlights more
the funky meaning of nil. This problems might exist more in heads of
the coders than the language/interpreter, since when learned all the
details how nil behaves you can work with it. However, even if so, a
good programming language should be aimed just as much to the heads to
coders than of cpus - thats all what in my opinion object oriented
programming was about - to better fit in the way we humans think
natively. The issue most directly on hand is type-safeness and let
errors happen where they occur instead of returning nil and error
later. local condition = some_function(); if conditonn then  --- will
always silently fail, even if some_function returned true.

I don't have wide-ranging experience with dynamic typed languages. Lua
is in fact the first one I used in a larger scale rather than these
small scriptles. I don't know of other examples of languages that
avoid nil. Javascript has it worse even two distinct values: null and
undefined, Python has None, Php has NULL. In static typed languages
like C or even Java the NULL pointer functions similar. But contrary
to static types, dynamics would not have to have a null type.

Removing nil has wide-ranging effects. First there is the obvious
cases of tables not having a key. Effect of nil-lessness: if the code
reads a key not there it raises an error(). Thats what be what would
be the scheme of that dialect, one wrong codelet, and immediate error.
There are yet many cases you would need to test for a table having a
key, in that case the ? operator is still free. foo.bar? is true if
foo has bar and false if it has not. (foo.bar? and foo.bar) would
become an idiom to be false if foo has not bar or the value if it has
- given you dont expect or want to differ to false as value, then you
would need a tad more code. As postfix operator it would be another
lookahead for the parser, but we humans are used for ? to be postfix.
But these are details.

Removing a table value is then table.unset(foo, bar). It may sound
less elegant than setting it to nil, but it hits the truth better to
what actually happens, and its just habit.

There are a few other places where nil-lessness would have an impact.
In Lua functions can be called with arbitrary few paramters and the
ones not given are filled with nil. Effect of nil-lessness: default
values come to rescue. If you call a function with less parameters
than it has default values, usual answer: error! You can even
differenciate in the function if you are called with a true default
value or any one given by the user.

do
  local itsdefault = {}
  function foo(a, b = isdefault)
    -- here you know if b is isdefault, or any value given by the user
  end
end

Local variables of course need to be either always initialized, or
raise an error if accessed before first initializiation. I'd prefer
first solution, as this would really allow TNIL to be removed as
primitive type from the VM.

And the last place I can think of is the next() of loop calls. These
functions use nil to signal an end of "stream". These have to be
changed to always return two values, a boolean if its on the end or
not, and the value - which can be anything if the boolean value is
false - Id use false for this.

Another simplificition or "cleanliness" modification would be, with
nil gone, you do not need implicit booleans interpretations anymore.
Only true is true and only false is false. If you need to test a value
to be anything than false, just write (value ~= false) please.

To sum it up:
pro: less confusion about nil as "second class value" (regardless if
that idiom exists)
pro: one primitive type and keyword less in a minimalistic language.
pro: errors (from typos or otherwise) are raised much closer to where
they happened than the nil value causing hickups later.
pro: while it makes the confusions for some around "arrays with holes"
not go away, they are much less likely to catch you.
neutral: the idiom about unsure keys is larger than currently, while
the ones that want to make sure the keys exist are shorter.
con: a new operator required for testing keys that are allowed to be not there.
con: a new basic function table.unset
con: double return values in some places where currently single return
sufficides.
con: something new is always fearsome and nil-lessness written modules
are incompatible with current lua.

Thanks for reading :) Axel