Find the nearest Waypoint from two optional locations using <? on a class with distance.

← Operators and Expressions · Ref: Q1231

Define a class with private fields, accessor methods, a custom <=> operator comparing distance, and 'default operator' last. Then use <? in a pure function.

  nearerWaypoint() as pure
    -> left as Waypoint, right as Waypoint
    <- rtn as Waypoint: left <? right

Classes are used instead of records when you need behaviour (methods). Waypoint has name() and distance() accessor methods because class fields are always private. The <? operator works identically on classes and records — it only requires <=> to be defined.

See Q1228 for <? on records.

Example

defines module qa.operators.coalesce.classmethod

  defines class

    Waypoint
      waypointName <- String()
      waypointDistance <- Float()

      Waypoint()
        ->
          name as String
          distance as Float
        waypointName :=: name
        waypointDistance :=: distance

      name() as pure
        <- rtn as String: waypointName

      distance() as pure
        <- rtn as Float: waypointDistance

      operator <=> as pure
        -> other as Waypoint
        <- rtn as Integer: waypointDistance <=> other.waypointDistance

      default operator

  defines function

    nearerWaypoint() as pure
      ->
        left as Waypoint
        right as Waypoint
      <- rtn as Waypoint: left <? right

  defines program

    CoalesceClassMethodDemo()
      stdout <- Stdout()

      // === BOTH SET — compares by distance ===

      basecamp <- Waypoint("Basecamp", 2.5)
      summit <- Waypoint("Summit", 8.7)
      nearer <- nearerWaypoint(basecamp, summit)
      stdout.println(`Nearer waypoint: ${nearer}`)

      // === ONE UNSET — returns the set one ===

      knownPoint <- Waypoint("Checkpoint", 5.0)
      unknownPoint <- Waypoint()
      available <- nearerWaypoint(knownPoint, unknownPoint)
      stdout.println(`Available waypoint: ${available}`)

      // === BOTH UNSET — result is unset ===

      lostA <- Waypoint()
      lostB <- Waypoint()
      noWaypoint <- nearerWaypoint(lostA, lostB)
      if noWaypoint?
        stdout.println(`Waypoint: ${noWaypoint}`)
      else
        stdout.println("No waypoint available")

      // === >? FOR FARTHEST ===

      farthest <- basecamp >? summit
      stdout.println(`Farthest waypoint: ${farthest}`)

Common mistakes

E07290 — Class fields are always private. To expose state, define accessor methods. Public fields are only allowed on records. See ek9 -h E07290 for details.

Incorrect:

      name as String: String()

Correct:

      name() as pure
        <- rtn as String: waypointName
Other ways to ask this
  • How do I use <? coalescing on a class instead of a record?
  • Given two optional Waypoint objects with distance fields, pick the nearer one.
  • In Java I'd implement Comparable on a class to use min(). What does EK9 use?
  • Migrating from Python where I use min(wp1, wp2, key=lambda w: w.distance) — what is the EK9 pattern?

Coming from another language?

Java: class Waypoint implements Comparable<Waypoint> with compareTo(). Python: class with __lt__ and min(). Kotlin: class with compareTo(). EK9: class with <=> operator, then left <? right.

Keywords: accessor, distance, coalescing, <?, method, waypoint, minimum, class