How do I use the Comparator function type for ordering?
← Generics · Ref: Q714
Comparator of T is a pure function type that takes two T values 't1' and 't2' and returns 'r' as Integer.
COMPARATOR SIGNATURE
Comparator of T takes two same-type parameters and returns their ordering:
cmp <- () is Comparator of String as pure function r: t1 <=> t2
Returns negative if t1 < t2, zero if equal, positive if t1 > t2.
ALWAYS PURE
Comparator is always pure — there is no impure variant. Ordering must be deterministic.
CUSTOM ORDERING
Reverse ordering by swapping t1 and t2:
reverseCmp <- () is Comparator of Integer as pure function r: t2 <=> t1
Compare by a derived property:
lengthCmp <- () is Comparator of String as pure function r: length t1 <=> length t2
THE <=> OPERATOR
EK9's comparison operator returns Integer: negative, zero, or positive.
See Q54 for pure function concepts. See Q89 for stream sort operations.
Example
defines module qa.genericsdeep.comparator defines function <?- Helper that finds the smaller of two values using a Comparator. -?> minimum() as pure -> first as String second as String cmp as Comparator of String <- result as String: first if cmp(first, second) > 0 result: second defines program ComparatorDemo() stdout <- Stdout() fruitA <- "apple" fruitB <- "banana" //Natural String ordering — uses 't1' and 't2' from Comparator signature natural <- () is Comparator of String as pure function r: t1 <=> t2 stdout.println(`'${fruitA}' vs '${fruitB}': ${natural(fruitA, fruitB)}`) //Reverse ordering — swap t1 and t2 reverse <- () is Comparator of String as pure function r: t2 <=> t1 stdout.println(`'${fruitA}' vs '${fruitB}' reversed: ${reverse(fruitA, fruitB)}`) //Compare by string length byLength <- () is Comparator of String as pure function r: length t1 <=> length t2 stdout.println(`'hi' vs 'hello' by length: ${byLength("hi", "hello")}`) //Minimum via Comparator delegate smaller <- minimum("zebra", fruitA, natural) stdout.println(`Minimum: ${smaller}`) //Integer Comparator intCmp <- () is Comparator of Integer as pure function r: t1 <=> t2 stdout.println(`42 vs 99: ${intCmp(42, 99)}`)
Common mistakes
E05150 — Comparator is always pure — dynamic functions extending Comparator must use 'as pure function', not just 'as function'. There is no impure variant of Comparator. See ek9 -h E05150 for details.
Incorrect:
() is Comparator of String as function
Correct:
() is Comparator of String as pure function
Other ways to ask this
- How do I create a Comparator of String for custom sorting?
- What is the Comparator function type signature in EK9?
- How do I implement a custom comparison with Comparator?
Coming from another language?
Java: java.util.Comparator<T> — not a @FunctionalInterface by design (has default methods), supports reversed(), thenComparing() composition, can have side effects. Kotlin: Comparator<T> from Java stdlib, or compareBy/compareByDescending helpers. Rust: Fn(&T, &T) -> Ordering — structural, uses Ordering enum not Integer. Go: func(T, T) int — by convention, or sort.Interface for types. C#: Comparer<T> or Comparison<T> delegate. EK9: Comparator of T is always pure — deterministic ordering guaranteed by compiler, takes (T, T) returns Integer, no impure variant exists.
Keywords: comparison, ordering, sort, comparator, delegate, pure, function-type, integer, generic, spaceship