lua-users home
lua-l archive

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


Thinking about the question, "could false be true?", which seems illogical,
I realised that there is an entirely consistent solution to the nil/false
"problem" (if indeed it is one) which is possibly more elegant (or less
disruptive to code) than adding "false".

This is basically a follow-up to my thought that in a given piece of code,
one does not really want to have three possibilities: nil/false/true; one
almost always wants two possibilities. The problem is defining which two:
nil/present or false/true.

So let's suppose that there exists a distinguished value which we will not
call "false" because it will test "true", but which we want to be
semantically "false". We'll call this "nil-but-true", and we don't need to
actually create it as a symbol, just to know that it exists (and that it
can serve as a table value).

Now let's define two "almost identity" operators:
     !a   is a unless a is nil, in which case it's "nil-but-true"
     ?a  is a unless a is "nil-but-true" in which case it's nil

!a is guaranteed to be a true value, and ?a is guaranteed not to return a
"false true" (or "true false" if you prefer)

(I know that those under the influence of C/Perl will find the use of ! to
mean True! a little odd, but I find it semantically correct. Not is not
"!". I don't know whose dumb idea that was, but there is no human language
I know in which ! indicates negation. Such people could use the C++ idiom
!!)

This solves pretty well all the problems presented. If you want to stuff a
value into a table, even if it might be nil, you say:

John.isMarried = !a

To get it back out again, recovering it's original truth value (or
returning nil if the key didn't exist), you say:

a = ?John.isMarried

To check if you know about John's marital status, you say

if John.isMarried then ...

to check what it is, assuming that unknown is tantamount to single, you say

if ?John.isMarried then ...

This also solves the ternary (a and b or c) issue:

    a and !b or c

means exactly "if a then b else c" provided that you don't need to
differentiate between nil and "nil-but-true" (and the whole point of this
exercise is to not have to differentiate.) If you needed to normalise the
above back to nil/known, you would call ? on the whole thing: ?(and and !b
or c)

It also solves that irritating problem with dostring where you want to be
able to test for success, but you also want to allow the string to return
nil. Returning !nil is exactly what is called for, and makes it easy to
test for later.

Now, let's take this idea one step further. With the above simple concept,
we can provide the consumer of a functional interface a way of specifying
"really nil, not the default value":
        foo(42, !nil)
That might be more semantically sound if ! were a postfix operator. nil!
not nothing, nil!

However, that's maybe a bit much to load interface consumers with, so let's
extend ! and ? a bit. We'll say that they are actually operators which
accept an arbitrary number of parameters. That's syntactically impossible
in Lua, but what I really mean is that you can use !expr in an exp (and not
just an exp1) environment, and it will return as many return values as it
received arguments, each of them converted as described above (identity
except for the value nil).

And we'll add one syntactic variant to the function() construct:
    function!(a, b, c) means apply ! to the actual vector provided.
Thus, a defaulted c would really be nil, whereas an explicitly provided nil
for c would be !nil

We don't need to extend the syntax of = or local =, because  we can use !
in an exp context:

a, b, c = "the question", !foo(42)

will let us know if foo(42) returned 0, 1 or 2 values: for example, c will
be nil if foo(42) returned less than two results, but a true value if it
returned 2 or more.

Now I think it also turns out to be useful to extend ? a little bit, by
giving it an associated tag method. Specifically, the definition of "?a"
could be:
   if a == nil, then return nil
   elseif a == "nil-but-true" then return nil
   elseif gettagmethod(a, "isfalse") then return tagmethod(a, "isfalse")()
   else return a
   end

This allows one to define one's own "pseudo-nil" values. Why would I want
to do that, you ask? Precisely because I want to be able to put my own
pseudovalues in tables; in particular, I'd like to be able to add
pseudokeys which are non-iterable. To solve that problem, I'd like for to
use the ? test in it's loop, but I'm perfectly content if there is a for
variant like
   for ?k, v in table do ... end
which does that for me. Or even
   for k, v in table do if ?k then
         ...
   end end
if necessary. (In other words, it's just more syntactic sugar).

Furthermore, I think the above tagmethod demonstrates what the actual value
"nil-but-true" turns out to be: it is exactly
   function(a) return nil end

So that if I set the isfalse tagmethod of my pseudofalse object to !nil,
and in particular if I set the isfalse tagmethod of !nil to !nil, the
implementation of ? becomes extremely streamlined (more so if calls to
constant functions are streamlined).

--- The more I think about this, the more I think ! and ? should be postfix
operators, for semantic reasons (or in Spanish parenthesized operators):
    if ¿John.secasó? then ... end
    if    John.isMarried? then ... end
    theAnswer = a and default! or foo(a)
etc.
However, postfix operators are an annoyance, so I'm not really being
serious.