false and nil

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
23 messages Options
12
Reply | Threaded
Open this post in threaded view
|

false and nil

Sam Putman
Hi,

I've been working a bit with SQL in Lua, which lead me to exercise a bit of curiousity at the REPL:

> = true and nil
nil

So far so good!

> = nil and true
nil

Excellent, Abelian, carry on

> = false and nil
false

.. Oh. That's not three-valued logic, then. Well at least

> = nil and false
nil

That's... not Abelian either.

I would like to propose that a future Lua have `false and nil` yield nil, and the same for `nil and false`.  This would give an identical semantics to the three-valued SQL null[0], and make the trio of values Abelian with respect to one another.


Sincerely,
-Sam Putman.
--
Special Circumstances
Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Sam Putman


On Mon, Jun 4, 2018 at 1:34 PM, Sam Putman <[hidden email]> wrote:

I would like to propose that a future Lua have `false and nil` yield nil, and the same for `nil and false`.  

Oops! It is `nil or false` which yields `false` and (I am suggesting) should yield `nil`. 

Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Sam Putman
I should add that I do understand what's happening here.

and & or aren't Abelian in general nor should be:

> = true and "boo"
"boo"

It is only in the case of nil that I suggest the falsiness propagate as a nil.  There are considerable advantages in reasoning power.
Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Hugo Musso Gualandi
In reply to this post by Sam Putman

To make the boolean operators non-commutative you would need to give up on short-circuiting evaluation. For example, consider:

    (i <= #xs and xs[i]:isgood())

If you try to evaluate the right operand when the left one is false (to check if it is nil or not) then xs[i] will evaluate to nil and trying to call the isgood method will result in a runtime error.

On Jun 4, 2018 5:44 PM, Sam Putman <[hidden email]> wrote:
I should add that I do understand what's happening here.

and & or aren't Abelian in general nor should be:

> = true and "boo"
"boo"

It is only in the case of nil that I suggest the falsiness propagate as a nil.  There are considerable advantages in reasoning power.
Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Sam Putman


On Mon, Jun 4, 2018 at 1:54 PM, Hugo Musso Gualandi <[hidden email]> wrote:

To make the boolean operators non-commutative you would need to give up on short-circuiting evaluation. For example, consider:

    (i <= #xs and xs[i]:isgood())

If you try to evaluate the right operand when the left one is false (to check if it is nil or not) then xs[i] will evaluate to nil and trying to call the isgood method will result in a runtime error.


That... is persuasive.  I had worked out the simple ternaries but didn't get as far as this case. 

Ah well.  `nil or false` could still be nil, but to no remaining advantage.
Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Alexander Nasonov
In reply to this post by Sam Putman
Sam Putman wrote:
> > = nil and false
> nil
>
> That's... not Abelian either.

A bit off-topic, but if you're looking for connections between
math and computer science, take a look at computable topology:

https://en.wikipedia.org/wiki/Computable_topology

--
Alex

Reply | Threaded
Open this post in threaded view
|

Re: false and nil

dyngeccetor8
In reply to this post by Sam Putman
On 06/04/2018 11:34 PM, Sam Putman wrote:

>> = true and nil
> nil
>[...]
>> = nil and true
> nil
>[...]
>> = false and nil
> false
>
> .. Oh. That's not three-valued logic, then. Well at least
>
>> = nil and false
> nil
>
> That's... not Abelian either.
>
> I would like to propose that a future Lua have `false and nil` yield nil,
> and the same for `nil and false`.  This would give an identical semantics
> to the three-valued SQL null[0], and make the trio of values Abelian with
> respect to one another.

Current behavior of "and" and "or" operators is equivalent to
following Lua-like functions.

--[[
  "..." means list of remained arguments.
  "is_empty(...)" means no arguments.
  "process(...)" is some function that will call "f_and" or "f_op"
    for remained elements.
]]

f_and =
  function(first, ...)
    if is_empty(...) then
      return first
    end
    if not first then
      return first
    else
      return process(...)
    end
  end

f_or =
  function(first, ...)
    if is_empty(...) then
      return first
    end
    if first then
      return first
    else
      return process(...)
    end
  end

-- Martin

Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Viacheslav Usov
On Tue, Jun 5, 2018 at 3:35 AM, dyngeccetor8 <[hidden email]> wrote:

> Current behavior of "and" and "or" operators is equivalent to following Lua-like functions.

The behaviour is documented in section 3.4.5, and the essential part of it is the "short-circuit evaluation; that is, the second operand is evaluated only if necessary". Your explanation is far more complicated than that and is technically incomplete and/or inconsistent anyway.

Cheers,
V.

Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Dirk Laurie-2
2018-06-05 10:03 GMT+02:00 Viacheslav Usov <[hidden email]>:

> On Tue, Jun 5, 2018 at 3:35 AM, dyngeccetor8 <[hidden email]>
> wrote:
>
>> Current behavior of "and" and "or" operators is equivalent to following
>> Lua-like functions.
>
> The behaviour is documented in section 3.4.5, and the essential part of it
> is the "short-circuit evaluation; that is, the second operand is evaluated
> only if necessary". Your explanation is far more complicated than that and
> is technically incomplete and/or inconsistent anyway.

The OP was playing an intellectual game (as is clear from his remark
"I should add that I do understand what's happening here.") The rest
of us don't want to play along, and would rather discuss the
curiosities of 'and' and 'or'. So (sorry, Sam) do I.

So with the thread well and truly hijacked, here is my 2¢'s worth.

I always find the distinction between true and `true` difficult to
make when writing documentation. It might show up only as a different
font. So I say "tests true" rather than "is true", and "a true value"
rather than "true".

The difficulty arises because 'boolean' is a late addition to Lua,
forcing a change in the semantics of 'and'/'or' so that the words can
be used as if they are boolean operators.

The and/or evaluation directives were already in Lua1.0, and simply
meant "do (or don't) do something depending on whether a certain value
is nil". Comparisons were not part of the picture. They did not result
in first-class values, you could only use them in conditional
statements,

When we get to Lua 3.0 (didn't test 2.x)  comparisons evaluate to 1 or
nil, which when seen as true or false and combined with and/or, behave
in the way you expect, so we don't need any new keywords or types.

Which is basically when the issue of nils in tables started. You are
memoizing a lot of expensive function evaluations, the result of each
of which is just a true/false value, and you can't distinguish between
a case already found false and a case not yet treated.

So they said: we don't want to allow nils in tables. We'll rather
create a whole new type so that you can store `false` instead.

Now we enter the modern era (Lua 5.0) From the point of view of
'and'/'or', nil and `false` both behave like nil did.  Not because it
is sensible from the point of view of evaluation directives (it isn't)
but because it has to be that way for boolean algebra to remain valid.
So 'and'/'or' is not really overloaded, but their semantics has
changed to accomodate the new datatype. You cannot longer blithely use
the idiom "x or default" when "false" is a reasonable value for x to
have.

As the OP has pointed out, the position of nil has become anomalous.
But this not because nil is special, it is because the class of values
that test false has another member besides `false`.

Now nils in tables is again on the table. They said: we don't want to
offer you a new value that behaves like nil except that the key/value
pair remains in the table when the value is nil. Instead, you can
compile with an option that always behaves that way. Except that
tbl[k]=nil will still mean that the key is removed.

Some of us noticed that in the code, though, such a new value is in
fact introduced. When we tried explaining in terms of the
implementation what happens, they were annoyed. Not helpful at all,
they said.

But the notion had other drawbacks, so nils-in-tables has been
scrapped. For now.

Watch this space.

Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Hugo Musso Gualandi
In reply to this post by Sam Putman

> I always find the distinction between true and `true` difficult to
> make when writing documentation. It might show up only as a different
> font. So I say "tests true" rather than "is true", and "a true value"
> rather than "true".

I like the terms "truthy" for "tests true" and "falsy"/"falsey" for the opposite. I believe they are fairly widespread as well.

I'd avoid saying "a true value". I think it is less clear than "a truthy value" or "a value that tests true"
Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Sam Putman
In reply to this post by Dirk Laurie-2


On Tue, Jun 5, 2018 at 3:24 AM, Dirk Laurie <[hidden email]> wrote:
2018-06-05 10:03 GMT+02:00 Viacheslav Usov <[hidden email]>:
> On Tue, Jun 5, 2018 at 3:35 AM, dyngeccetor8 <[hidden email]>
> wrote:
>
>> Current behavior of "and" and "or" operators is equivalent to following
>> Lua-like functions.
>
> The behaviour is documented in section 3.4.5, and the essential part of it
> is the "short-circuit evaluation; that is, the second operand is evaluated
> only if necessary". Your explanation is far more complicated than that and
> is technically incomplete and/or inconsistent anyway.

The OP was playing an intellectual game (as is clear from his remark
"I should add that I do understand what's happening here.") The rest
of us don't want to play along, and would rather discuss the
curiosities of 'and' and 'or'. So (sorry, Sam) do I.


That's not entirely fair.  I was neck deep in SQL, and wanted to see if evaluation
could be adjusted to match the three-valued logic.

The advantages are considerable!
 
So with the thread well and truly hijacked, here is my 2¢'s worth.


It isn't a hijack imho.  The short-circuit behavior is desirable, in a way that trumps 
the utility of a nil == null semantics. 

I didn't know the first thing about how we got here, thanks for that!

One could imagine a language where, say, the ternary operator, as well as "&", "|", "!",
follow a lazy evaluative logic, while "and", "or", and "not" follow a three-valued Boolean
logic, and were thus required to evaluate eagerly.

Wouldn't be Lua, though.
Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Javier Guerra Giraldez


On 5 June 2018 at 17:29, Sam Putman <[hidden email]> wrote:
That's not entirely fair.  I was neck deep in SQL, and wanted to see if evaluation
could be adjusted to match the three-valued logic.

The advantages are considerable!


perhaps it's because of long exposure to c-style short circuiting logic; but i generally find the SQL NULL behaviour heavy and hard to tame.  any non-trivial expression quickly becomes a tangle of special cases to handle NULLs, and choosing the exact operator/cast function is a nightmare.

can you point some references that make it all "click" and see what i'm missing? 


--
Javier
Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Sam Putman


On Tue, Jun 5, 2018 at 10:02 AM, Javier Guerra Giraldez <[hidden email]> wrote:


On 5 June 2018 at 17:29, Sam Putman <[hidden email]> wrote:
That's not entirely fair.  I was neck deep in SQL, and wanted to see if evaluation
could be adjusted to match the three-valued logic.

The advantages are considerable!


perhaps it's because of long exposure to c-style short circuiting logic; but i generally find the SQL NULL behaviour heavy and hard to tame.  any non-trivial expression quickly becomes a tangle of special cases to handle NULLs, and choosing the exact operator/cast function is a nightmare.

can you point some references that make it all "click" and see what i'm missing? 



SQL is old and therefore messy, you have awfulness like Oracle casting "" to NULL.

Also, SQL values get translated to language values, and casting SQL null to Java null 
is a mistake, C NULL would of course be a disaster.

In "pure" three-valued SQL logic, NULL means "this value is not known". 

Consider the difference between someone who tells the barista "Prince" when asked
his name, and Prince, the artist.  Prince the artist has last_name = false; Prince the 
coffee enthusiast has last_name = NULL. 
Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Sam Putman


On Tue, Jun 5, 2018 at 10:08 AM, Sam Putman <[hidden email]> wrote:

Also, SQL values get translated to language values, and casting SQL null to Java null 
is a mistake, C NULL would of course be a disaster.


Perhaps the most important: SQL cannot specify an evaluation order, to give 
the query planner flexibility in execution.

This makes a short circuiting left-to-right logic impossible.  

Because SQL is declarative, this doesn't have to be eager. Lua would have no alternative,
and likes to choose the sensible thing, such as left-to-right evaluation of parameters, and
getting out of logical chains just as soon as it's able. 

Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Russell Haley
In reply to this post by Dirk Laurie-2


On Tue, Jun 5, 2018 at 3:24 AM, Dirk Laurie <[hidden email]> wrote:
2018-06-05 10:03 GMT+02:00 Viacheslav Usov <[hidden email]>:
> On Tue, Jun 5, 2018 at 3:35 AM, dyngeccetor8 <[hidden email]>
> wrote:
>
>> Current behavior of "and" and "or" operators is equivalent to following
>> Lua-like functions.
>
> The behaviour is documented in section 3.4.5, and the essential part of it
> is the "short-circuit evaluation; that is, the second operand is evaluated
> only if necessary". Your explanation is far more complicated than that and
> is technically incomplete and/or inconsistent anyway.

The OP was playing an intellectual game (as is clear from his remark
"I should add that I do understand what's happening here.") The rest
of us don't want to play along, and would rather discuss the
curiosities of 'and' and 'or'. So (sorry, Sam) do I.

So with the thread well and truly hijacked, here is my 2¢'s worth.

I always find the distinction between true and `true` difficult to
make when writing documentation. It might show up only as a different
font. So I say "tests true" rather than "is true", and "a true value"
rather than "true".

The difficulty arises because 'boolean' is a late addition to Lua,
forcing a change in the semantics of 'and'/'or' so that the words can
be used as if they are boolean operators.

The and/or evaluation directives were already in Lua1.0, and simply
meant "do (or don't) do something depending on whether a certain value
is nil". Comparisons were not part of the picture. They did not result
in first-class values, you could only use them in conditional
statements,

When we get to Lua 3.0 (didn't test 2.x)  comparisons evaluate to 1 or
nil, which when seen as true or false and combined with and/or, behave
in the way you expect, so we don't need any new keywords or types.

Which is basically when the issue of nils in tables started. You are
memoizing a lot of expensive function evaluations, the result of each
of which is just a true/false value, and you can't distinguish between
a case already found false and a case not yet treated.

So they said: we don't want to allow nils in tables. We'll rather
create a whole new type so that you can store `false` instead.

Now we enter the modern era (Lua 5.0) From the point of view of
'and'/'or', nil and `false` both behave like nil did.  Not because it
is sensible from the point of view of evaluation directives (it isn't)
but because it has to be that way for boolean algebra to remain valid.
So 'and'/'or' is not really overloaded, but their semantics has
changed to accomodate the new datatype. You cannot longer blithely use
the idiom "x or default" when "false" is a reasonable value for x to
have.

As the OP has pointed out, the position of nil has become anomalous.
But this not because nil is special, it is because the class of values
that test false has another member besides `false`.

Now nils in tables is again on the table. They said: we don't want to
offer you a new value that behaves like nil except that the key/value
pair remains in the table when the value is nil. Instead, you can
compile with an option that always behaves that way. Except that
tbl[k]=nil will still mean that the key is removed.

Some of us noticed that in the code, though, such a new value is in
fact introduced. When we tried explaining in terms of the
implementation what happens, they were annoyed. Not helpful at all,
they said.
Hi Dirk, your Lua history lesson was excellent but I'm struggling to understand the preceding comment. Could you clarify what was "noticed" (are you referring to undef?) and who "they" were?


But the notion had other drawbacks, so nils-in-tables has been
scrapped. For now.
I wasn't really clear about why the NIL_IN_TABLE option was retracted.  I thought it was because there was more work remaining than could be reasonably completed before the unannounced 5.4 release date?


Watch this space.


Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Russell Haley
In reply to this post by Sam Putman


On Tue, Jun 5, 2018 at 10:08 AM, Sam Putman <[hidden email]> wrote:


On Tue, Jun 5, 2018 at 10:02 AM, Javier Guerra Giraldez <[hidden email]> wrote:


On 5 June 2018 at 17:29, Sam Putman <[hidden email]> wrote:
That's not entirely fair.  I was neck deep in SQL, and wanted to see if evaluation
could be adjusted to match the three-valued logic.

The advantages are considerable!


perhaps it's because of long exposure to c-style short circuiting logic; but i generally find the SQL NULL behaviour heavy and hard to tame.  any non-trivial expression quickly becomes a tangle of special cases to handle NULLs, and choosing the exact operator/cast function is a nightmare.

can you point some references that make it all "click" and see what i'm missing? 



SQL is old and therefore messy, you have awfulness like Oracle casting "" to NULL.

Also, SQL values get translated to language values, and casting SQL null to Java null 
is a mistake, C NULL would of course be a disaster.
I can still remember the day and a half of pain when learning that C# null is not the same as SQL Server null. Nope, you need to use DBNull.Value to check for NULL in a column. Grrrr.


In "pure" three-valued SQL logic, NULL means "this value is not known". 

Consider the difference between someone who tells the barista "Prince" when asked
his name, and Prince, the artist.  Prince the artist has last_name = false; Prince the 
coffee enthusiast has last_name = NULL. 

Reply | Threaded
Open this post in threaded view
|

Re: false and nil

dyngeccetor8
In reply to this post by Viacheslav Usov
On 06/05/2018 11:03 AM, Viacheslav Usov wrote:

> On Tue, Jun 5, 2018 at 3:35 AM, dyngeccetor8 <[hidden email]>
> wrote:
>
>> Current behavior of "and" and "or" operators is equivalent to following
> Lua-like functions.
>
> The behaviour is documented in section 3.4.5, and the essential part of it
> is the "short-circuit evaluation; that is, the second operand is evaluated
> only if necessary". Your explanation is far more complicated than that and
> is technically incomplete and/or inconsistent anyway.

Section 3.4.5 describes it nicely indeed:

  The negation operator "not" always returns "false" or "true". The
  conjunction operator "and" returns its first argument if this value
  is "false" or "nil"; otherwise, and returns its second argument. The
  disjunction operator "or" returns its first argument if this value
  is different from "nil" and "false"; otherwise, "or" returns its
  second argument. Both "and" and "or" use short-circuit evaluation;
  that is, the second operand is evaluated only if necessary.

I've showed how this logic may be implemented via Lua functions. Yes,
that illustration is technically incomplete (for better expression
power). But why it is inconsistent? From my view that functions is
logically  correct.

-- Martin

Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Dirk Laurie-2
In reply to this post by Russell Haley
2018-06-05 23:31 GMT+02:00 Russell Haley <[hidden email]>:
>
> On Tue, Jun 5, 2018 at 3:24 AM, Dirk Laurie <[hidden email]> wrote:
>>

> Hi Dirk, your Lua history lesson was excellent but I'm struggling to
> understand the preceding comment. Could you clarify what was "noticed" (are
> you referring to undef?) and who "they" were?

If you grep around in the Lua 5.4-work1 source code starting with
LUA_NILINTABLE, and just following strange words,
you eventually discover

(a) a new `lua_type LUA_TEMPTY`
(b) a predefined value `luaH_emptyobject of that type`

which is stored in tables instead of `nil` when you compile with
LUA_NILINTABLE defined. `undef` is therefore needed for when you want
to store a real nil wiith its normal behaviour.

I apologize for the grammatical solecism "they". Although I consider
my command of English to be near-native, it has never been my home
language, and traces of Afrikaans occasionally shine through. ("shine
through" is another such.) Afrikaans does not have an impersonal
pronoun and the same word that also means "they, them, their" is used
for the purpose.

>> But the notion had other drawbacks, so nils-in-tables has been
>> scrapped. For now.

> I wasn't really clear about why the NIL_IN_TABLE option was retracted.  I
> thought it was because there was more work remaining than could be
> reasonably completed before the unannounced 5.4 release date?

I don't there are planned release dates. Lua has always gone through
as many work, alpha and beta versions as it takes for a reasonably
well-tested product to emerge.

There was a long thread with plenty of discussion, including delight,
dissent and counter-proposals. A highly respected active member of
this list made several long posts, signing off with the conclusion "
In thinking things over, I don't like the undef idea.  I think it
introduces too many issues."

Between the lines, I read that the Lua team itself is not unanimous on
this one, and the implementation issue was just the last straw.

Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Viacheslav Usov
In reply to this post by dyngeccetor8
On Wed, Jun 6, 2018 at 12:37 AM, dyngeccetor8 <[hidden email]> wrote:

> But why it is inconsistent? From my view that functions is logically  correct.

Because it is incomplete, it is difficult to say why exactly it is inconsistent. A few things that seemed odd to me:

1. Lua describes 'and' and 'or' is binary operator Your description had variadic functions, so they can be called with zero, one or more than two arguments, and what does that mean? Fundamentally, Lua ensures that 'and' and 'or' have exactly two operands statically, your description cannot do that. 

2. The or-function seemed prone to infinite recursion if called without arguments.

3. In order to have short-circuit operation your functions would need to receive their arguments not as pre-evaluated values of "operands", but rather as functions computing those values. Ignoring that this is syntactically very different from true 'and' and 'or', the treatment of the first argument was still like that of a pre-evaluated value, rather than a value-producing function.

Cheers,
V.
Reply | Threaded
Open this post in threaded view
|

Re: false and nil

Dirk Laurie-2
2018-06-06 9:15 GMT+02:00 Viacheslav Usov <[hidden email]>:

> 1. Lua describes 'and' and 'or' is binary operator

This puts the finger on the sore spot. The manual is misleading.

Since they use short-circuit evaluation, they are not operators. They
are evaluation directives: control structures that return a value. For
boolean arguments, they happen to behave like operators would. We
really should have had '&&' and '||' for logical consitency.

Of course, from Lua 5.3 on you can try to make '&' and '|' do the job:

debug.setmetatable(true,{__band = function(a,b) return a and b end;
__bor = function(a,b) return a or b end; __bnot = function(a) return
not a end})

but the precedence then is highly confusing.

12