How do comparison operators work between constrained types and their base types?
← Advanced Type System · Ref: Q717
Constrained types inherit comparison operators from the base type with dual signatures: each operator works with both the constrained type and the raw base type.
DUAL SIGNATURE PATTERN
Every comparison operator gets two forms:
isEqual1 <- age1 == age2 //DrivingAge == DrivingAge -> Boolean isEqual2 <- age1 == 25 //DrivingAge == Integer -> Boolean
This means you can compare constrained values directly with literals.
WHY DUAL SIGNATURES MATTER
Without dual signatures, you would need to wrap every literal:
isEqual <- age1 == DrivingAge(25) //works but verbose isEqual <- age1 == 25 //also works — much cleaner
The compiler generates both forms automatically.
ALL COMPARISON OPERATORS
The full set of inherited comparisons (when base type has them):
== equality <> not equal < less than <= less or equal > greater than >= greater or equal <=> spaceship (returns Integer)
OPERATORS FROM BASE TYPE ONLY
If the base type lacks an operator, the constrained type does not have it either. A record with only == and <> will not support <, <=, >, >= on its constrained type.
CONTAINS AND MATCHES
String-constrained types inherit contains and matches:
hasAlice <- name1 contains "Alice" //String has contains matched <- name1 matches /^[A-Z]/ //String has matches
Integer-constrained types do NOT have these.
See Q257 for constrained type overview. See Q716 for arithmetic operators. See Q718 for the promote operator.
Example
defines module qa.advancedtypes.constrainedcomparisons defines type DrivingAge as Integer constrain as >= 16 and <= 100 Name as String constrain as matches /^[a-zA-Z -]+$/ defines program ConstrainedComparisonDemo() stdout <- Stdout() // === EQUALITY: CT == CT and CT == BaseType === age1 <- DrivingAge(25) age2 <- DrivingAge(30) isEqual <- age1 == age2 stdout.println(`25 == 30: ${isEqual}`) twentyFive <- 25 isEqualBase <- age1 == twentyFive stdout.println(`25 == 25: ${isEqualBase}`) // === NOT EQUAL === notEqual <- age1 <> age2 stdout.println(`25 <> 30: ${notEqual}`) ninetyNine <- 99 notEqualBase <- age1 <> ninetyNine stdout.println(`25 <> 99: ${notEqualBase}`) // === ORDERING: CT < CT and CT < BaseType === isLess <- age1 < age2 stdout.println(`25 < 30: ${isLess}`) fifty <- 50 isLessBase <- age1 < fifty stdout.println(`25 < 50: ${isLessBase}`) isGreater <- age2 > age1 stdout.println(`30 > 25: ${isGreater}`) twenty <- 20 isGreaterBase <- age2 > twenty stdout.println(`30 > 20: ${isGreaterBase}`) // === SPACESHIP OPERATOR === cmpResult <- age1 <=> age2 stdout.println(`25 <=> 30: ${cmpResult}`) // === STRING-CONSTRAINED: contains and matches === name1 <- Name("Alice") name2 <- Name("Bob") same <- name1 == name2 stdout.println(`Alice == Bob: ${same}`) sameBase <- name1 == "Alice" stdout.println(`Alice == 'Alice': ${sameBase}`) matched <- name1 matches /^A/ stdout.println(`Alice matches ^A: ${matched}`)
Common mistakes
E50060 — DrivingAge has no equals() method in EK9. Use the == operator for equality comparison. See ek9 -h E50060 for details.
Incorrect:
isEqual <- age1.equals(age2)
Correct:
isEqual <- age1 == age2
E50060 — Name has no equals() method in EK9. Use the == operator for equality comparison. See ek9 -h E50060 for details.
Incorrect:
sameBase <- name1.equals("Alice")
Correct:
sameBase <- name1 == "Alice"
Other ways to ask this
- Can I compare a constrained type with its base type value?
- Why does DrivingAge < Integer work?
- What comparison operators does a constrained type inherit?
Coming from another language?
Java: no constrained types, comparisons use equals()/compareTo() methods. Python: no type constraints, comparison via __eq__/__lt__ etc. Rust: newtype pattern requires implementing PartialEq/PartialOrd traits manually. Go: type aliases inherit comparison operators but no value constraints. Kotlin: value classes require manual operator definitions. EK9: constrained types automatically inherit all comparison operators from the base type with dual signatures (CT==CT and CT==BaseType), enabling natural comparisons with both constrained values and raw literals.
Keywords: dual, inherit, equals, constrained, operator, comparison, matches, signature, contains