E01096: '??' and '??=' are not EK9 operators - EK9 is designed so that a value is never absent (it may be unset), so there is nothing for them to test; write 'x ?: y' to use 'y' when 'x' is unset, and 'x :=? y' to assign 'y' only when 'x' is unset
What went wrong
'??' is not an EK9 operator. In languages that have it (C#, JavaScript, Swift, PHP) it means "the left side, unless it is null, then the right side". EK9 is designed so that a value is never absent - there is no null, and a variable must be given a value before it is read, though that value may be unset. So '??' is not needed: 'x ?? y' would never use 'y' - it would give 'x' whatever 'y' is:
rtn: name ?? fallback //removed: write '?:', which uses the right when the left is unset
'??=' (C#, JavaScript, PHP: assign when the left is null) is removed for the same reason and gives this same error, naming ':=?' (assign only if unset):
rtn ??= fallback //removed: write ':=?', which assigns only when the left is unset
The grammar does not drop the '??' and '??=' tokens - it keeps them only to give this error, as it keeps 'break' and 'return'.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1059 (Why is there no ?? null coalescing operator in EK9, and how do I default an unset value?)
- ek9 -q 243 (How do coalescing operators handle unset values in EK9?)
- ek9 -q 1091 (Provide a fallback display name when the user name is unset.)
How to fix it
Decide what the left side may be, then write that.
If the left may be UNSET (a value that exists but has no meaningful value, such as an Integer() or a String()), use '?:' - it gives the left when it is set and the right when it is not:
rtn: name ?: fallback
To give an existing variable a value only when it is unset, use ':=?' instead of the removed '??=':
rtn :=? fallback
If the left is an Optional or a Result, check it with '?' first, then read it.
This is a suggestion, never an automatic repair: '??' and '??=' look only for an absent left, while '?:' and ':=?' look for an unset one, so they do not always mean the same, and the compiler will not choose for you.
Common causes
- Habit from C#, JavaScript, Swift or PHP, where '??' supplies a default (Kotlin writes it '?:', as EK9 does)
- Habit from C#, JavaScript or PHP, where 'x ??= y' assigns 'y' when 'x' is null
- AI-written code that has not met EK9 before
- Reading 'null coalescing' in another language's notes and expecting the same operator
See also
- E01095: '<=?' and '>=?' were removed (the other removed coalescing operators)
- E08269: a coalescing operator mixed with a different binary operator without parentheses
- E08094: a literal on the left of '?:' - it is always set, so the right is never used
- https://ek9.io/operators.html#coalescing
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E01096: '??' and '??=' are not EK9 operators - EK9 is designed so that a value is never absent (it may be unset), so there is nothing for them to test; write 'x ?: y' to use 'y' when 'x' is unset, and 'x :=? y' to assign 'y' only when 'x' is unset
#!ek9 defines module error.e01096.bad defines function nameOrDefault() -> name as String fallback as String <- rtn as String? rtn: name ?? fallback //removed: write '?:', which uses the right when the left is unset nameOrAssigned() -> name as String fallback as String <- rtn as String: name rtn ??= fallback //removed: write ':=?', which assigns only when the left is unset
Fixed: Write '?:' - it gives the right when the left is unset
#!ek9 defines module error.e01096.good defines function nameOrDefault() -> name as String fallback as String <- rtn as String? rtn: name ?: fallback
Fixed: Write ':=?' - it assigns only when the left is unset
#!ek9 defines module error.e01096.good.assign defines function nameOrDefault() -> name as String fallback as String <- rtn as String: name rtn :=? fallback
Questions and answers
These Q&A entries show E01096 and its fix: