[erlang-questions] strictly less-than (Re: [erlang-questions] Ordered set and DETS)

Nicholas Frechette zeno490@REDACTED
Tue Sep 7 01:04:14 CEST 2010


I see what you mean by 'number' < 'tuple' defining an order. Essentially,
there is a category missing to (on that same page/section):

The arguments may be of different data types. The following order is
defined:

number < atom < reference < fun < port < pid < tuple < list < bit string

'number' could be split into two: integer and floating point. Something like:
integer < floating point < atom < reference < etc.
Such that:
1 < 1.0 -> true instead of false?
1 > 1.0 -> false as currently

This would allow lists:sort to sort but then, the behavior would be one that
isn't intuitive. (ie: 1 < 0.5 -> true)
The other way around this is as you suggested to add matching strict
operators (:>, :<, :=>, :<=) but then that still won't fix lists:sort
(without a code change to it obviously). And when one is doing sorting, one
will have to stick to one set of operators or the other, else the order
isn't potentially defined. Though this seems to apply to numbers only as the
order is explicitly defined for any other pair of terms. Your operators
would thus only be required for comparing numbers.
Perhaps it would make more sense to have =:= sometime coerce so that == and
=:= are equivalent for numbers only? Since there isn't any defined ordering
for them without that operator coercing (if you mix <, > and =:=).
Incidentaly, matching would then work with numbers:
case 1.0 of
    1 -> currently_doesnt_match;
    _ -> currently_always_matches
end.
(Side note: Does the compiler optimize the above and strip it since it's a
constant branch?)

Looking elsewhere, I believe in lisp the following applies:
(< 1 1.0) -> false
(< 1 2.0) -> true
(= 1 1.0) -> true

(eq 3 3) might be true or false, depending on the implementation.
(eq 3 3.0) is false.
(eq 3.0 3.0) might be true or false, depending on the implementation.

(eql 3 3) is true.
(eql 3 3.0) is false.
(eql 3.0 3.0) is true.

(equal 3 3) is true.
(equal 3 3.0) is false.
(equal 3.0 3.0) is true.

(equalp 3 3) is true.
(equalp 3 3.0) is true.
(equalp 3.0 3.0) is true.

This is the case because in lisp +-=<>*/ etc are functions that coerce.
Given a list of terms, a single function would be evaluated on them to sort
them, a function you'd explicitly define (or defined in the library). This
could lead to weird results if you mix types:
(< 1 "foo") -> true (no order defined for these, unlike in erlang)
(< "foo" 1) -> true
(= 1 "foo") -> false
Sadly, my lisp is a bit rusty and I'm not sure I can adequately explain the
above behavior. Nonetheless, when sorting or otherwise extracting an
ordering between terms, in lisp one will most likely end up using the
comparison operators and not the equality predicates (eq, eql, equal,
equalp) thus avoiding the issue you ran into (at least when not mixing
types, I presume when one is mixing types that can't coerce, one has to
provide a function in order to get strict ordering). Maybe someone with more
lisp experience than I have can elaborate further here but that is my
understanding.

Thus imo, when ordering things in erlang, one should use the comparison
operators that coerce and use the exact match operators when one is
attempting to match. Otherwise, you are setting yourself up for a world of
pain.

lists:sort is probably a "stable sort" in that if elements are equal, they
appear in the sorted list in the order they appeared in the unsorted one
which explains the behavior you see:
lists:sort([2, 1, 1.0]) -> [1, 1.0, 2]
lists:sort([2, 1.0, 1]) -> [1.0, 1, 2]
lists:sort([1, 2, 3, 2.0]) -> [1, 2, 2.0, 3]
lists:sort([1, 2.0, 3, 2]) -> [1, 2.0, 2, 3]

Sorry for the lenghty email.
Nicholas

On Mon, Sep 6, 2010 at 11:30 AM, Ulf Wiger
<ulf.wiger@REDACTED>wrote:

> On 09/06/2010 05:03 PM, Nicholas Frechette wrote:
> > Is that not the expected behavior per the erlang doc?
> > http://www.erlang.org/doc/reference_manual/expressions.html
>
> Well, yes, but that in itself is no guarantee that it is a
> good solution. ;-)
>
>
> > Incidentaly, what would you expect of the following:
> > 1 < {foo, 2}
> > 1 > {foo, 2}
> > 1 == {foo, 2}
> > 1 =:= {foo, 2}
>
> There is nothing strange or unambiguous there.
> Erlang has a global term comparison order so e.g. 1 < {foo,2} is
> perfectly well defined.
>
> The int->float coercion is fine... until it's not. That's why
> we have =:= and =/=, because in some cases, 1 and 1.0 really
> are distinctly different.
>
> I have managed to get by programming erlang for the better part of
> 17 years before I was finaly bitten by this, so I'm perfectly willing
> to go on happily without ever seeing this corrected.
>
> However, I really don't see the disadvantage of ensuring that the
> global comparison order can be guaranteed across the board, without
> any surprising corner cases, and I think lists:sort/1 et al should
> really be able to provide such guarantees.
>
> BTW, there was another interesting edge case some years ago, that
> proved very troublesome for mnesia. Pids did not sort the same
> way on all connected nodes in a distributed erlang network. This broke
> some fundamental assumptions in mnesia's deadlock detection algorithm.
> It has long-since been fixed, but having a truly universal sort order
> really is a very good thing.
>
> BR,
> Ulf W
>


More information about the erlang-questions mailing list