How do coalescing operators handle unset values in EK9?
← Operators and Expressions · Ref: Q243
EK9 provides coalescing operators that safely handle unset values. These are expression-level operators (not implementable on your types) that the compiler handles directly.
NO NULL COALESCING (??)
There is no ?? operator (E01096). In Swift, C# or JavaScript it tests for null; EK9 is designed so that a value is never absent (it may be unset), so it would have nothing to test. Use ?: instead.
COALESCE (ELVIS) (?:)
The ?: operator checks if the left is both present AND set (via isSet). If the left is absent or unset, it returns the right.
result <- possiblyUnset ?: fallback
COMPARISON COALESCING OPERATORS
These operators compare two values, handling the case where one or both might be unset:
<? (lesser coalescing): returns the lesser value, or whichever is valid >? (greater coalescing): returns the greater value, or whichever is valid
TIE RULE: when the two values compare equal (<=> gives 0) both operators return the LEFT operand; swap the operands to get the right one. The inclusive forms that once existed were removed (E01095): <? and >? already give the left operand on a tie.
Priority rules: If left is invalid, return right. If right is invalid, return left. If both valid, compare and return the winner.
minimum <- a <? b maximum <- a >? b
NOTE: :=? is NOT a coalescing operator. It is an ASSIGNMENT operator that assigns only if the target is unset. See Q1152 for :=? details. See Q1226 for <? vs :=? contrast.
REPLACING VERBOSE IF/ELSE
Without coalescing:
if a? if b? if a < b result: a else result: b else result: a else result: b
With coalescing:
result <- a <? b
One line replaces a nested if/else tree.
See Q75 for guard switch. See Q161 for Dict safe access. See Q168 for fallback values. See Q239 for comparison operators. See Q238 for the complete operator set.
Example
#!ek9 defines module qa.operators.coalescing defines program CoalescingDemo() stdout <- Stdout() // === ELVIS OPERATOR ?: === name <- String() displayName <- name ?: "Anonymous" stdout.println(`Display name: ${displayName}`) // === COMPARISON COALESCING OPERATORS === a <- 10 b <- 20 minimum <- a <? b maximum <- a >? b stdout.println(`Minimum: ${minimum}`) stdout.println(`Maximum: ${maximum}`) // === CHAINED COALESCING === primary <- String() secondary <- String() fallback <- "last-resort" chosen <- primary ?: secondary ?: fallback stdout.println(`Chosen: ${chosen}`)
Common mistakes
E01096 — '??' is not an EK9 operator. '?:' gives the right when the left is unset. See ek9 -h E01096 for details.
Incorrect:
displayName <- name ?? "Anonymous"
Correct:
displayName <- name ?: "Anonymous"
E50030 — The result of a coalescing operator is one of its operands, so the operands must share a type. A String and an Integer share only Any, which is rejected at the operator (E50030). See ek9 -h E50030 for details.
Incorrect:
displayName <- name ?: 42
Correct:
displayName <- name ?: "Anonymous"
Other ways to ask this
- What is the null coalescing operator in EK9?
- How does the Elvis operator work in EK9?
- How do I pick the lesser or greater of two possibly unset values?
- What are the coalescing operators in EK9?
- How do coalescing comparators work in EK9?
- What do <? and >? mean in EK9?
- Does EK9 have a ?? null coalescing operator like Swift or C#?
- How does null coalescing work in EK9?
Coming from another language?
Java: ternary x != null ? x : default, no null coalescing operator, Optional.orElse(). Python: x if x is not None else default, or shorthand x or default (falsy gotcha). Rust: unwrap_or(), unwrap_or_else(), no null concept. Go: if x == nil then default, no ternary or coalescing. Kotlin: ?: elvis operator for null, no comparison coalescing operators. Swift: ?? nil coalescing (EK9 has no ??, E01096), no equivalent of ?: isSet check or <? >? comparison coalescing operators. JavaScript: ?? null coalescing (ES2020), || logical or fallback. EK9: ?: (isSet check), <? >? (comparison coalescing operators), :=? (assign-if-unset).
Keywords: absent, assignment, coalesce, coalescing, comparator, conditional, default, elvis, expression, fallback, greater, isset, lesser, maximum, migrate, minimum, null, operator, safe, swift, unset