E08269: a coalescing operator ('?:', '<?', '>?') mixed with a different binary operator must be parenthesised - it binds tighter than arithmetic, comparison and logic, so write '(a + b) ?: c' or 'a + (b ?: c)' to say which is meant
What went wrong
A coalescing operator - coalesce (Elvis) '?:' or one of the comparison coalescing operators '<?', '>?' - is mixed with a DIFFERENT binary operator without parentheses. EK9 does not let precedence decide which is applied first, because the two readings give different answers on an unset value. 'first + second ?: fallback' reads as 'first + (second ?: fallback)', because '?:' binds tighter than '+'; when 'first' is unset the sum is unset - the fallback never applied to the sum.
Other languages disagree about this precedence (Kotlin puts '?:' below '+', C# and JavaScript put their '??' below '=='), so whichever reading you expected, someone reading your code expects the other.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 2060 (Why must I put parentheses around '?:' when I mix it with '+' or '=='?)
Each of these is E08269:
- sum <- first + second ?: fallback //'?:' inside '+'
- fallenBack <- first ?: second + fallback //also '?:' inside '+': (first ?: second) + fallback
- same <- first == second ?: fallback
- both <- ready ?: false and other
- smallest <- first <? second + limit //'+' takes '<?' as an operand
- bounded <- first <? second >? floor //two DIFFERENT coalescing operators
- chosen <- first ?: second <? fallback //'?:' and '<?' are different operators
- power <- first ?: second ^ 2 //'^' binds tighter than '?:'
Each of these is fine:
- //The sum, or the fallback when the sum is unset
- wholeSum <- (first + second) ?: fallback
- //First plus (second, or the fallback)
- oneOperand <- first + (second ?: fallback)
- //The SAME operator chained reads one way only
- chosen <- first ?: second ?: fallback
- smallest <- first <? second <? third
- bounded <- (first <? second) >? floor
How to fix it
- Decide which operator is meant to apply first and parenthesise it: '(first + second) ?: fallback' falls back when the whole sum is unset; 'first + (second ?: fallback)' falls back for one operand only.
- Chains of the same coalescing operator ('a ?: b ?: c', 'a <? b <? c') need no parentheses.
Common causes
- Expecting Kotlin's precedence, where '?:' binds below '+'
- A long one-line expression combining '<~>', '?:' and '<'
- Writing 'flag ?: false and other' to default a Boolean before combining it
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E08269: a coalescing operator ('?:', '<?', '>?') mixed with a different binary operator must be parenthesised - it binds tighter than arithmetic, comparison and logic, so write '(a + b) ?: c' or 'a + (b ?: c)' to say which is meant
#!ek9 defines module error.e08269.bad defines function total() -> first as Integer second as Integer fallback as Integer <- rtn as Integer? rtn: first + second ?: fallback mixedForms() -> first as Integer second as Integer fallback as Integer limit as Integer floor as Integer ready as Boolean other as Boolean sum <- first + second ?: fallback //'?:' inside '+' fallenBack <- first ?: second + fallback //also '?:' inside '+': (first ?: second) + fallback same <- first == second ?: fallback both <- ready ?: false and other smallest <- first <? second + limit //'+' takes '<?' as an operand bounded <- first <? second >? floor //two DIFFERENT coalescing operators chosen <- first ?: second <? fallback //'?:' and '<?' are different operators power <- first ?: second ^ 2 //'^' binds tighter than '?:'
Fixed: Parenthesise the operand you mean
#!ek9 defines module error.e08269.good defines function total() -> first as Integer second as Integer fallback as Integer <- rtn as Integer? rtn: (first + second) ?: fallback
Fixed: Parenthesise to say which applies first; a chain of the same operator reads one way only
#!ek9 defines module error.e08269.good.forms defines function readings() -> first as Integer second as Integer third as Integer fallback as Integer floor as Integer <- rtn as String? //The sum, or the fallback when the sum is unset wholeSum <- (first + second) ?: fallback //First plus (second, or the fallback) oneOperand <- first + (second ?: fallback) //The SAME operator chained reads one way only chosen <- first ?: second ?: fallback smallest <- first <? second <? third bounded <- (first <? second) >? floor rtn: `${wholeSum} ${oneOperand} ${chosen} ${smallest} ${bounded}`
Questions and answers
These Q&A entries show E08269 and its fix: