Why does the compiler say my 'if x?' can never be true (E08089)?
← Data Flow Safety · Ref: Q2256
'if x?' asks whether x has a value. When the compiler is SURE x is unset at that point, the answer is always no, so the block can never run - it is dead code, and EK9 reports it (E08089). EK9 has no warnings, so the check fires only when the compiler is certain.
THE USUAL CAUSES
- the value was made by a built-in type's no-argument constructor, which makes it present but unset:
retries <- Integer() if retries? //E08089: retries is always unset here Stdout().println($retries)
- the check repeats one the code has already answered: in the 'else' of 'if x?', or inside 'if not x?', x is unset, so a second 'x?' there can never be true.
THE FIX
Take the value from where it may be set - a function, a parameter, a lookup - and the check genuinely decides. If it is always unset at that point, the block is dead: delete it, or give the value a value first. To give a default where it is unset, use 'if not x?' with ':=', or ':=?' on a value that MAY be unset.
The mirror is E08088: 'if x?' on a value the compiler is sure is SET is always true (Q559). How the compiler decides what is sure, and when it gives up, is Q2255.
Example
#!ek9 defines module qa.dataflowsafety.issetnevertrue defines function //The compiler does not look inside a function for what it returns, so the checks below decide at run time. configuredRetries() <- rtn as Integer: 5 savedName() -> known as Boolean <- rtn as String: String() if known rtn := "Steve" greet() -> known as Boolean stdout <- Stdout() name <- savedName(known) if name? stdout.println(`name: ${name}`) else stdout.println("no name saved") defines program IsSetNeverTrueDemo() stdout <- Stdout() retries <- configuredRetries() if retries? stdout.println(`retries: ${retries}`) if not retries? retries := 3 stdout.println(`retries now: ${retries}`) greet(true) greet(false)
Common mistakes
E08089 — Integer() makes an unset Integer, so 'if retries?' can never be true. Take the value from where it may be set. See ek9 -h E08089 for details.
Incorrect:
retries <- Integer()
Correct:
retries <- configuredRetries()
E08089 — In the else of 'if name?' the name is unset, so a second 'name?' there can never be true. Use a plain else. See ek9 -h E08089 for details.
Incorrect:
else if name? stdout.println("no name saved")
Correct:
else stdout.println("no name saved")
Other ways to ask this
- What is E08089 isSet check is always false?
- Why is my isSet check always false?
- Why can my '?' check never succeed?
- Why does 'if count?' after 'count <- Integer()' fail to compile?
Coming from another language?
Java: 'if (x != null)' straight after 'x = null' compiles; an IDE may warn that the condition is always false. Kotlin reports some such checks as warnings. EK9 has no null and no warnings: 'Integer()' is a present but UNSET Integer, and an 'x?' that can never be true is reported as E08089 - only when the compiler is sure.
Keywords: ?, E08089, Integer(), String(), always false, data flow, dead code, isSet, never true, unset