Why is there no ?? null coalescing operator in EK9, and how do I default an unset value?
← Operators and Expressions · Ref: Q1059
EK9 has no ?? operator (E01096), and no null keyword. Its tri-state model has THREE states - ABSENT (no object at all), present but UNSET (an object with no meaningful value, e.g. String()), and SET. EK9 is designed so that a value you declare and assign is never absent, so a null-test like ?? would have nothing to find: 'name ?? "default"' would give name, whatever the default was.
To default an UNSET value use ?: (COALESCE, Elvis):
name <- String() present, but UNSET b <- name ?: "stranger" b is "stranger"
?: returns name only if it is SET. If name is unset (or absent) the result is "default". To assign a default in place, use :=? (nickname :=? "stranger"); there is no ??= either (E01096).
The distinction from other languages:
Java: name != null ? name : "default" checks null Kotlin: name ?: "default" checks null Swift, C#, JavaScript: name ?? "default" checks null; there is no such operator in EK9 EK9: name ?: "default" checks isSet
In EK9, a variable can exist but be UNSET. This is not the same as null. An unset String is a String object that has no meaningful value yet. It still exists - you can call ? on it to check.
name <- String() // name exists, but is UNSET stdout.println(`${name?}`) // false (unset) name := "Alice" // now SET stdout.println(`${name?}`) // true
If BOTH sides of ?: are unset, the result is unset.
See Q243 for all coalescing operators. See Q898 for ? is not ternary. See Q883 for tri-state semantics.
Example
#!ek9 defines module qa.operators.coalescingisset defines function //No nickname saved: unset savedNickname() <- rtn as String: String() defines program CoalescingDemo() stdout <- Stdout() //An UNSET String: the object is present, it just has no value name <- String() stdout.println(`name is set: ${name?}`) //?: tests SET-NESS - name is unset, so the default is used defaulted <- name ?: "stranger" stdout.println(`Hello ${defaulted}`) //Set the name name := "Alice" stdout.println(`name is set: ${name?}`) //Now name is set, so ?: returns it viaElvis <- name ?: "visitor" stdout.println(`Hello ${viaElvis}`) //:=? gives an unset variable a value, and leaves a set one alone nickname <- savedNickname() nickname :=? "stranger" stdout.println(`nickname is ${nickname}`)
Common mistakes
E01096 — '??' is not an EK9 operator: EK9 is designed so that a value is never absent (it may be unset), so '??' would have nothing to test. '?:' gives the right when the left is unset. See ek9 -h E01096 for details.
Incorrect:
defaulted <- name ?? "stranger"
Correct:
defaulted <- name ?: "stranger"
E01096 — '??=' is not an EK9 operator either: EK9 is designed so that a value is never absent (it may be unset), so there is nothing for it to test. ':=?' assigns only when the variable is unset. See ek9 -h E01096 for details.
Incorrect:
nickname ??= "stranger"
Correct:
nickname :=? "stranger"
E01073 — 'null' does not exist in EK9 — a variable is either set or unset (tri-state), so assign a real value rather than 'null'. See ek9 -h E01073 for details.
Incorrect:
name := null
Correct:
name := "Alice"
Other ways to ask this
- Why is ?? not an operator in EK9?
- What do the coalescing operators actually check in EK9?
- Why can't I write name ?? "default" in EK9?
- Should I use ?: or :=? to default an unset value in EK9?
- Does ?: check for null in EK9?
- Is there a ??= null coalescing assignment in EK9?
Coming from another language?
Java: ternary with null check. Kotlin: ?: (elvis) checks null. JavaScript/C#/Swift: ?? (nullish coalescing) checks null - EK9 has no ?? or ??= (E01096). EK9: ?: checks that the value is SET - use ?: to default an unset value. EK9 has no null.
Keywords: absent, coalescing, default, elvis, isset, null, operator, unset