How do I implement comparison operators on a record for sorting?

← Operators and Expressions · Ref: Q1049

Implement the <=> (spaceship) operator on your record. Then derive <, >, <=, >= from it. All comparison operators must be pure.

  defines record
    Priority
      level as Integer: 0
      operator <=> as pure
        -> other as Priority
        <- rtn as Integer: level <=> other.level
      operator < as pure
        -> other as Priority
        <- rtn as Boolean: (this <=> other) < 0
      operator > as pure
        -> other as Priority
        <- rtn as Boolean: (this <=> other) > 0
      operator <= as pure
        -> other as Priority
        <- rtn as Boolean: (this <=> other) <= 0
      operator >= as pure
        -> other as Priority
        <- rtn as Boolean: (this <=> other) >= 0

Once these are defined, you can sort lists and use coalescing operators:

  smaller <- priorityA <? priorityB
  larger <- priorityA >? priorityB

The coalescing operators <? and >? return the lesser or greater value. They work because the comparison operators are defined.

See Q1050 for coalescing operators on a class. See Q239 for comparison ordering. See Q1051 for operators on traits.

Example

defines module qa.operators.comparisonrecord

  defines record

    Priority
      level as Integer: 0
      label as String: String()

      Priority()
        ->
          level as Integer
          label as String
        this.level :=: level
        this.label :=: label

      operator <=> as pure
        -> other as Priority
        <- rtn as Integer: level <=> other.level

      operator < as pure
        -> other as Priority
        <- rtn as Boolean: (this <=> other) < 0

      operator > as pure
        -> other as Priority
        <- rtn as Boolean: (this <=> other) > 0

      operator <= as pure
        -> other as Priority
        <- rtn as Boolean: (this <=> other) <= 0

      operator >= as pure
        -> other as Priority
        <- rtn as Boolean: (this <=> other) >= 0

      default operator

  defines program

    ComparisonRecordDemo()
      stdout <- Stdout()

      high <- Priority(10, "Critical")
      medium <- Priority(5, "Normal")
      low <- Priority(1, "Low")

      stdout.println(`High > Low: ${high > low}`)
      stdout.println(`Medium <= High: ${medium <= high}`)

      //Coalescing: get the lesser/greater
      lesser <- high <? medium
      greater <- low >? medium
      stdout.println(`Lesser: ${lesser}`)
      stdout.println(`Greater: ${greater}`)

Common mistakes

E07520 — The < operator must return Boolean, not Integer. Use <=> for Integer comparison results, < for Boolean.

Incorrect:

      operator < as pure
        -> other as Priority
        <- rtn as Integer: level - other.level

Correct:

      operator < as pure
        -> other as Priority
        <- rtn as Boolean: (this <=> other) < 0
Other ways to ask this
  • How do <, >, <=, >= work on a record?
  • Show me comparison operators on a custom record
  • How do I make a record sortable in EK9?

Coming from another language?

Java: implements Comparable. Python: __lt__, __gt__, etc. Rust: derive Ord. EK9: define <=> then derive <, >, <=, >= from it.

Keywords: record, sort, operator, comparison, spaceship