Write an EK9 class with comparison operators so I can sort a list of them.

← Functions and Methods · Ref: Q1065

Define the <=> (spaceship) operator: it is the type's sameness, and the compiler generates ==, <>, <, <=, > and >= from it. Writing any of those for the type itself is an error (E07181). Add a hand-written #? that hashes what <=> compares (E07184 otherwise), $ for string display, and ? because a class with properties needs it (E07235 otherwise).

defines class

  Product
    productName as String: String()
    price as Float: 0.0
    Product()
      ->
        productName as String
        price as Float
      this.productName :=: productName
      this.price :=: price
    override operator ? as pure
      <- rtn as Boolean: productName? and price?
    operator <=> as pure
      -> other as Product
      <- rtn as Integer: price <=> other.price
    operator #? as pure
      <- rtn as Integer: #? price
    operator $ as pure
      <- rtn as String: `${productName}: ${price}`

Now you can sort, and use every comparison:

  cat products | sort > stdout
  cheapest <- first <? second

For a different ordering (by name, say) write a comparator function and use 'sort by', never a second <=>.

See Q1049 for comparison on records. See Q1047 for hashcode. See Q1055 for default operator.

Example

defines module qa.functions.writesortableclass

  defines class

    Product
      productName as String: String()
      price as Float: 0.0

      default private Product()

      Product()
        ->
          productName as String
          price as Float
        this.productName :=: productName
        this.price :=: price

      operator <=> as pure
        -> other as Product
        <- rtn as Integer: price <=> other.price

      //== <> < <= > >= are all generated from <=>; #? hashes what <=> compares
      operator #? as pure
        <- rtn as Integer: #? price

      override operator ? as pure
        <- rtn as Boolean: productName? and price?

      operator $ as pure
        <- rtn as String: `${productName}: ${price}`

  defines program

    SortableClassDemo()
      stdout <- Stdout()

      products <- [
        Product("Widget", 9.99),
        Product("Gadget", 24.99),
        Product("Doohickey", 4.99)
      ]

      //Sort by price (uses <=> operator)
      stdout.println("Sorted by price:")
      cat products | sort > stdout

      //Get cheapest
      cheapest <- Product("Widget", 9.99) <? Product("Gadget", 24.99)
      stdout.println(`Cheapest: ${cheapest}`)

Common mistakes

E07181 — The <=> operator is the type's sameness and the compiler generates ==, <>, <, <=, > and >= from it. Writing == for the type itself is error E07181. See ek9 -h E07181 for details.

Incorrect:

      operator <=> as pure
        -> other as Product
        <- rtn as Integer: price <=> other.price

      operator == as pure
        -> other as Product
        <- rtn as Boolean: price == other.price

Correct:

      operator <=> as pure
        -> other as Product
        <- rtn as Integer: price <=> other.price
Other ways to ask this
  • How do I make a class sortable in EK9?
  • Write a class I can use in a sorted stream pipeline
  • Code a class with all comparison operators

Coming from another language?

Java: implements Comparable<T>. Python: __lt__, __gt__. Rust: derive Ord. EK9: define <=> once; the compiler generates ==, <>, <, <=, >, >= from it.

Keywords: coder, code, write, operator, comparison, class, sort