E08088: isSet check is always true based on data flow analysis
What went wrong
This isSet check (?) is always true based on data flow analysis. The variable is provably SET at this point — either from a literal assignment, a guard that already proved the variable is set, or a prior assignment from a constructor call.
The same applies to set-checks you do not write as '?' (D7). A guard's own gate is a set-check: 'if seven <- 7' always enters, as does 'if late :=? 5' on a provably unset 'late'. Re-testing a guard's own target in its then/with condition - 'if v <- f() then v?' or 'if x :=? f() then x?' - is always true: that condition only runs once the gate has passed. And an 'x?' that is one operand of an 'and' condition is judged like a whole condition: 'if x := 7 then x? and ready'.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 559 (Why does EK9 reject my isSet check as redundant?)
- ek9 -q 2255 (How does the EK9 compiler decide a variable is definitely...)
- ek9 -q 640 (When is an isSet check on a collection genuinely needed...)
- ek9 -q 311 (What code quality checks does the EK9 compiler perform?)
How to fix it
- Remove the redundant isSet check and unwrap the code
- If the variable was assigned from a literal, the check is unnecessary
- If inside a guard's true-branch, the guard already guarantees the variable is set
- Verify this isn't a copy-paste error from a different variable
- A guard over a known value: declare the variable plainly and drop the 'if' (or test what you meant to test); after a guard, drop 'then v?' - the guard has checked it
- 'if x := f() then x?' (a blind re-point and gate) is fine: nothing proves f() set
Common causes
- Variable assigned from a literal (String, Integer, Boolean) and then checked with ?
- Declaration guard (if x <- expr()) followed by a redundant x? check in the body
- Defensive coding habit from other languages where null checks are needed after assignment
- Refactoring moved an assignment before a check but didn't remove the check
- Collection (List, Dict) constructed and then checked with ? — collections are always SET when created
- Optional constructed with a value and then checked with ? — always SET
- A class, component or service with no fields (counting inherited ones) constructed and then checked with ? (a Stateless() then tested with 's?') — its '?' is generated and answers true whenever it is present
- A guard over a literal or a collection constructor: 'if seven <- 7', 'if names <- List() of String'
- 'then v?' after 'if v <- f()' or 'if v :=? f()' — the guard's gate already checked v
- 'if x := 7 then x? and ready' — the 'x?' operand is known true
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E08088: isSet check is always true based on data flow analysis
#!ek9 defines module error.e08088.bad defines function checkStringLiteralAlwaysSet() <- result as String: String() greeting <- "hello" if greeting? result: greeting checkIntegerLiteralAlwaysSet() <- result as String: String() count <- 42 if count? result: $count checkBooleanLiteralAlwaysSet() <- result as String: String() isEnabled <- true if isEnabled? result: $isEnabled
Fixed: Use a value that is known to be set directly
#!ek9 defines module error.e08088.good defines function checkStringLiteralAlwaysSet() <- result as String: String() greeting <- "hello" result: greeting checkMaybeSet() -> greeting as String <- result as String: String() if greeting? result: greeting
Questions and answers
These Q&A entries show E08088 and its fix: