Why is 'count <- Integer()' then 'count++' reported as an error (E08096)?
← Data Flow Safety · Ref: Q2253
'Integer()' makes an Integer that is present but UNSET, and '++' on an unset Integer keeps it unset - the operator has no starting value to add one to, and it never invents one. So 'count++' after 'count <- Integer()' can never give 'count' a value, however often it runs. The compiler is sure of both facts, so it reports E08096 at the '++':
count <- Integer() count++ //E08096: 'count' is always unset here stdout.println($count)
The fix is to start from a value: 'count <- 0'. The same is true of '+=', '-=', '*=' and '/=' on every built-in type that has them - start a String from "" (Q2251), a sum from 0 and a product from 1 (Q2252), a Float from 0.0, a Duration from PT0S, a Millisecond from 0ms.
INSIDE 'if not x?'
There the value is unset by the condition itself, so adding to it can do nothing. Give it a value instead, with ':=' - there ':=?' would always apply, so the compiler asks for ':=' (E08097):
if not total? total := 0 total += 1
ONLY WHEN SURE
EK9 has no warnings, so an error must be certain. E08096 fires only where the value is known to be unset - made by a no-argument constructor such as 'Integer()' or 'String()', or inside 'if not x?' - and the operator is one that is known to keep it unset. A value from a function call may be set, so the compiler stays silent; at run time an unset one is still left unset, as the program below shows. A loop is checked over every pass: a total that is only ever added to inside the loop stays unset after it, but one also assigned in the loop is left alone. Your own types define their own operators, so they are never reported.
A copy ':=:' DOES set an unset value - it is not one of these operators. See Q936 for the '?' set check and Q880 for why EK9 has no null.
Example
#!ek9 defines module qa.dataflowsafety.operatorkeepsvalueunset defines function topUp() -> amount as Integer <- total as Integer: amount if not total? total := 0 total += 1 unsetSupply() <- rtn as Integer: Integer() defines program OperatorKeepsValueUnsetDemo() stdout <- Stdout() count <- 0 count++ count++ stdout.println(`count: ${count}`) stdout.println(`topped up: ${topUp(Integer())}`) stdout.println(`kept: ${topUp(5)}`) //From a function call the compiler cannot be sure, so it is silent - and at run time it stays unset supplied <- unsetSupply() supplied += 1 stdout.println(`supplied unset, after +=: set=${supplied?}`) elapsed <- PT0S elapsed += PT1H30M stdout.println(`elapsed: ${elapsed}`) waited <- 0ms waited += 750ms stdout.println(`waited: ${waited}`)
Common mistakes
E08096 — Integer() makes an unset Integer and '++' keeps it unset, so the count never gets a value. Start from 0. See ek9 -h E08096 for details.
Incorrect:
count <- Integer()
Correct:
count <- 0
E08096 — Inside 'if not total?' the value is unset, and '+=' keeps it unset. Give it a value with ':='. See ek9 -h E08096 for details.
Incorrect:
total += 0
Correct:
total := 0
Other ways to ask this
- What does E08096 'always unset here' mean?
- Why can '+=' or '++' never give an unset value a value?
- Why does the compiler stop me adding to an unset Integer?
- When does EK9 report an operator that keeps a value unset?
Coming from another language?
Java: Integer count = null; count++ throws NullPointerException at run time. Python: count = None; count += 1 raises TypeError. EK9: 'count <- Integer()' is a present but UNSET Integer; '++' keeps it unset, which would fail silently, so the compiler reports E08096 when it is sure. Start from 0.
Keywords: ++, +=, :=?, E08096, Integer(), String(), always unset, data flow, keeps unset, tri-state, unset