How are defaulted comparison operators derived - does a defaulted == agree with my <=>?

← Operators and Expressions · Ref: Q1398

Every defaulted comparison is answered by the type's <=> when it has one. A defaulted == is '(a <=> b) == 0', <> is '(a <=> b) <> 0', and <, <=, >, >= compare the <=> result with zero - so a defaulted operator can never disagree with the type's ordering.

WRITE <=>, DEFAULT THE REST

  Ticket
    id as Integer: 0
    holder as String: ""
    operator <=> as pure
      -> other as Ticket
      <- rtn as Integer: id <=> other.id
    operator #? as pure
      <- rtn as Integer: #?id
    default operator    //generates ==, <>, <, <=, >, >= and operator ? as well

A hand-written <=> needs a hand-written #? hashing what it compares (E07184).
Tickets are ordered by id alone, so two tickets with the same id are ==, even though their holders differ.

NO ORDERING, NO <=>

Some types have == but no <=> - Dict, List, Optional, Result. A type with such a field cannot be ordered: a bare 'default operator' gives it == (field by field) and <> (its negation), but no <, <=, >, >= or <=> - using one is E07620.

EXPLICIT DEFAULTS

When requesting operators one at a time, request the sameness only: 'default operator <=>' (or 'default operator ==' for a type that cannot be ordered). ==, <>, <, <=, >, >= are always generated from it and are never written or requested - 'default operator <>' is E07181.

A bare 'default operator' generates every operator the type does not write itself, even beside an operator of the same name that takes a different argument (an ==(Integer) does not stop ==(Ticket) being generated).

Example

defines module qa.operators.defaulted.comparisons

  defines class

    Ticket
      id as Integer: 0
      holder as String: ""

      Ticket()
        ->
          identity as Integer
          name as String
        id: identity
        holder: name

      operator <=> as pure
        -> other as Ticket
        <- rtn as Integer: id <=> other.id

      //A hand-written <=> needs a hand-written #? hashing what it compares
      operator #? as pure
        <- rtn as Integer: #?id

      default operator

    Badge
      code as String: ""

      Badge()
        -> text as String
        code: text

      default operator ?
      default operator <=>

  defines record

    Settings
      values as Dict of (String, Integer): Dict() of (String, Integer)
      default operator

  defines program

    DefaultedComparisons()
      stdout <- Stdout()
      first <- Ticket(7, "Steve")
      second <- Ticket(7, "Alex")
      stdout.println($(first == second))
      stdout.println($(first < Ticket(8, "Sam")))
      stdout.println($(Badge("a") <> Badge("b")))
      stdout.println($(Settings() == Settings()))

Common mistakes

E07620 — Settings has a Dict field, and a Dict has no <=>, so Settings cannot be ordered: its bare 'default operator' generates == and <> but no ordering operators.

Incorrect:

stdout.println($(Settings() < Settings()))

Correct:

stdout.println($(Settings() == Settings()))

E07181 — <> is always generated from the type's sameness (<=> or ==), so it is never written or requested - 'default operator <>' is E07181. Request (or write) the sameness, <=>, and <> comes with it.

Incorrect:

default operator <>

Correct:

default operator <=>
Other ways to ask this
  • If I write <=> myself, what does 'default operator' generate for == and <>?
  • Why is == true when two objects differ in a field <=> ignores?
  • Why can't I use < on a record that has a Dict field?
  • Why is 'default operator <>' rejected when I only want inequality?

Coming from another language?

Java: equals() and compareTo() are written independently and 'consistent with equals' is only a documented recommendation - TreeSet and HashSet can disagree about the same objects. Kotlin: data classes generate equals() but not compareTo(), so the two can drift. Rust: #[derive(PartialEq, PartialOrd)] derives both field by field, but a hand-written Ord beside a derived PartialEq can disagree. EK9: the defaulted comparisons are generated from <=>, so they agree with it by construction.

Keywords: E07181, equals, ==, compareTo, <>, default, operator, derived, orderable, comparison, E07620, consistent, ordering, Dict, equality, <=>