How do comparison and ordering operators work in EK9?
← Operators and Expressions · Ref: Q239
EK9 provides a comprehensive set of comparison and ordering operators. All comparison operators MUST be pure, take exactly 1 argument, and return specific types. If either operand is unset, the result is unset.
EQUALITY AND INEQUALITY
The == operator tests equality and returns Boolean. The <> operator tests inequality and returns Boolean. Both take one argument of the same type.
operator == as pure -> other as MyType <- rtn as Boolean: ...
ORDERING
The <, >, <=, >= operators test ordering and return Boolean. They take one argument.
if score1 > score2 stdout.println("Higher")
THREE-WAY COMPARISON (SPACESHIP)
The <=> operator returns Integer: negative if less, zero if equal, positive if greater. This is the foundation for sorting.
operator <=> as pure -> other as MyType <- rtn as Integer: ...
When you implement <=>, you typically derive <, >, <=, >= from it.
FUZZY COMPARISON
The <~> operator returns Integer representing a distance or similarity score. For String, it returns the Levenshtein edit distance. The lower the value, the more similar.
distance <- "hello" <~> "hallo" stdout.println(`Edit distance: ${distance}`)
CONTAINS AND MATCHES
The 'contains' operator checks if one value contains another. The 'matches' operator checks pattern matching (e.g., regex). Both are pure, take 1 argument, and return Boolean.
if greeting contains "hello" stdout.println("Found") if email matches /[a-z]+@[a-z]+\.[a-z]+/ stdout.println("Valid")
UNSET PROPAGATION
If either operand is unset, comparison results are unset (not false). This prevents silent logic errors with missing data.
See Q96 for class operators. See Q238 for the complete operator set. See Q243 for coalescing operators that handle unset values.
Example
defines module qa.operators.comparison defines class Temperature celsius <- Float() Temperature() as pure -> celsius as Float this.celsius :=: celsius operator == as pure -> other as Temperature <- rtn as Boolean: celsius == other.celsius operator <> as pure -> other as Temperature <- rtn as Boolean: celsius <> other.celsius operator <=> as pure -> other as Temperature <- rtn as Integer: celsius <=> other.celsius operator < as pure -> other as Temperature <- rtn as Boolean: celsius < other.celsius operator > as pure -> other as Temperature <- rtn as Boolean: celsius > other.celsius operator <= as pure -> other as Temperature <- rtn as Boolean: celsius <= other.celsius operator >= as pure -> other as Temperature <- rtn as Boolean: celsius >= other.celsius operator $ as pure <- rtn as String: `${celsius}C` override operator ? as pure <- rtn as Boolean: celsius? defines program ComparisonDemo() stdout <- Stdout() freezing <- Temperature(0.0) boiling <- Temperature(100.0) body <- Temperature(37.0) // === EQUALITY AND INEQUALITY === stdout.println(`Equal: ${freezing == boiling}`) stdout.println(`Not equal: ${freezing <> boiling}`) // === ORDERING === stdout.println(`Freezing < boiling: ${freezing < boiling}`) stdout.println(`Body >= freezing: ${body >= freezing}`) // === THREE-WAY COMPARISON === cmp <- freezing <=> boiling stdout.println(`Compare: ${cmp}`) // === FUZZY COMPARISON ON STRINGS === reference <- "hello" distance <- reference <~> "hallo" stdout.println(`Fuzzy distance: ${distance}`) // === CONTAINS AND MATCHES === greeting <- "hello world" stdout.println(`Contains hello: ${greeting contains "hello"}`)
Common mistakes
E07500 — The spaceship comparison operator must be marked 'as pure' because comparisons cannot have side effects. Omitting 'as pure' triggers E07500. See ek9 -h E07500 for details.
Incorrect:
operator <=>
Correct:
operator <=> as pure
E07550 — The <=> operator must return Integer for three-way comparison ordering. Returning String instead triggers E07550. See ek9 -h E07550 for details.
Incorrect:
<- rtn as String: celsius <=> other.celsius
Correct:
<- rtn as Integer: celsius <=> other.celsius
E07520 — The < operator must return Boolean (true or false). Returning Integer instead triggers E07520. See ek9 -h E07520 for details.
Incorrect:
<- rtn as Integer: celsius < other.celsius
Correct:
<- rtn as Boolean: celsius < other.celsius
Other ways to ask this
- How do I compare two objects in EK9?
- What is the spaceship operator in EK9?
- How does fuzzy matching work with the <~> operator?
Coming from another language?
Java: equals() for equality, compareTo() for ordering (returns int), no fuzzy match built-in. Python: __eq__, __lt__, __gt__ etc., functools.total_ordering derives from __lt__ and __eq__. Rust: PartialEq, Eq, PartialOrd, Ord traits, derived with #[derive()]. Go: no operator overloading, manual comparison functions. Kotlin: compareTo() operator, == delegates to equals(). JavaScript: no custom comparisons, == with type coercion problems. EK9: ==, <>, <, >, <=, >= return Boolean, <=> returns Integer, <~> returns fuzzy distance, all must be pure with 1 argument.
Keywords: fuzzy, matches, Integer, operator, sort, expression, greater, Boolean, equal, contains, spaceship, unset, less, comparison, ordering