lua-users home
lua-l archive

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

Paul Matthews:

> > I would like to use LUA as the embedded scripting language in a
> > relational database engine, but I need nil and nan ordering to work
> > in the correct manner (ie IEEE for NaN). And quite simply it is
> > currently impossible to convince LUA to work in the correct manner,
> > because there is only one tag 'lt'.

Reuben Thomas:

> So for those who didn't believe me before (when I merely wanted to
> compare sets), here's a solid real world reason for fixing ordering!


I'll repeat what I said last time (in response to Reuben): that's fine, but
keep your hands off of "==".

I understand (and sympathise with) the point that is being made, but object
identity (Lua's ==) is too fundamental to the language to change. If a
syntactic solution (as opposed to the library function cmp) is desired,
then let's use different symbols.

Lua is a table-based language. It is fundamental to the logic of Lua that
if a == b, then T[a] == T[b] for any table T. This would not hold true for
definitions of == other than object identity.

It is superficially tempting to say that < is "the same" in a complete
ordering as in a partial ordering, but it's not. For example, standard sort
algorithms do not work on partial orders, so you have to know whether a
type is partially ordered or not before you sort it. Similarly, in a
complete ordering, if it is not true that a < b then it is certainly true
that b >= a, which makes a difference when you're writing if statements.
Subtle logic problems can occur, such as the following:

if a < b then "do something"
  elseif a > b then "do something else"
  else "assume that a == b"

This is correct for complete orders; if a and b are members of a partially
ordered type, it fails.

Lua does not currently have syntactic support for partial ordering. Perhaps
it should. I would like to see Lua conform with IEEE-754 where possible,
and IEEE-754 "numbers" are partially-ordered. If that's interesting to more
than a handful of people with specific issues, then perhaps we should look
at operators such as <·, ·>, and ·=· (or choose your symbols, those of you
without access to centre-dots on your keyboards might prefer something

If Lua were to go down that path, I would recommend keeping the "lt" tag
method exactly as it is, and adding a "partial_le" tag method attached to
whatever the partial-less-than-or-equal-to operator turns out to be; in the
absence of the "partial_le" tag method, partial-order comparators could try
for an "lt" tag method before deciding that the objects are incomparable.

PS: It is an oddity that IEEE-754 numbers are partially-ordered. Few
languages correctly support this, and I venture to guess that few
programmers care. The fact that NaN is not equal to NaN raises almost as
much debate as the "one true false" debate in Lua (and other languages).
Many C compilers will optimise away the test a==a, although that is a
perfectly legitimate way of testing for a being NaN (at least, I think it
is perfectly legitimate).

One possibly completely bizarre idea would be to represent nil as "NaN",
and redefine == such that nil == nil is nil. That would be consistent with
IEEE-754; it would not bother me as much as other changes to == (because
nil is not a valid table index anyway); and it would provide the behaviour
that Paul is looking for in numeric comparisons with nil. Testing for nil
could be accomplished with "not". Unfortunately, that is not compatible
with having two false values. I still think having two false values is a
mistake (I just had to say that).

If nil were NaN and false didn't exist, then == could return nil or its
second argument, which is actually reasonably useful. And so could < and
friends; if a < b returned either nil or b, then you could meaningfully
write a < b < c (and the computation could be short-circuited). That's
somewhat attractive (and generalisable to non-numeric comparisons).

I suppose that's all moot because of the popularity of "false".  As a
(possibly) final interjection in that debate, for anyone who has read this
far, let me ask the following question: suppose I'm writing a library which
defines a predicate function P. What value should P return if the predicate
is not true, false or nil? How do I decide? If I'm the consumer of
libraries which defined predicates P and Q, how do I know what will be the
behaviour of:

T[x] = P(x) and Q(x)

Will the key x exist in T or not? If T is some opaque type from some other
library, what interactions could this seemingly innocuous statement

I remain convinced that nil/false should be resolved in the definition of
T, not in the definitions of P and Q: predicates should have a single way
of reporting false, and the definition of persistent objects should define
whether that value is deletion or definition.