Why does AI generate null checks instead of guards in EK9?
← What AI Gets Wrong About EK9 · Ref: Q277
AI models generate 'if result != null', 'if result is not None', or 'if result == null return' in EK9. There is no null in EK9. The keyword does not exist. EK9 uses a tri-state model (absent, unset, set) with guard expressions.
THE AI MISTAKE
AI imports null-checking patterns from Java (null), Python (None), JavaScript (null/undefined), or Go (nil). None of these concepts exist in EK9.
THE EK9 TRI-STATE MODEL
Every EK9 object exists in one of three states:
Absent: does not exist (missing Dict key, empty Optional) Present but unset: exists but has no meaningful value (String() creates unset String) Present and set: exists with a valid value (String("hello") is set)
THE ? OPERATOR
Check whether an object is set with the ? operator:
if name? stdout.println(name)
This replaces null checks. The ? operator returns Boolean.
GUARD EXPRESSIONS
Guards combine assignment with the ? check in a single step:
if record <- findRecord(key) stdout.println(`Found: ${record}`)
The guard 'if record <- findRecord(key)' declares 'record', assigns the result, and checks if it is set. If unset, the block is skipped entirely. No null check needed.
GUARDS WORK EVERYWHERE
The same guard syntax works identically in all control flow:
while connection <- getActive() transferData(connection) for entry <- nextEntry() process(entry) switch config <- loadConfig() case .port > 8000 useHighPort(config)
GUARDED ASSIGNMENT FOR DEFAULTS
The ':=?' operator assigns only if the target is unset:
host <- String() host :=? "localhost"
This replaces the null coalescing pattern (Java's 'x != null ? x : default').
See Q29 for tri-state semantics. See Q74 for guard expressions. See Q85 for guards in all control flow. See Q243 for coalescing operators. See Q281 for verifying AI code.
Example
defines module qa.ai.mistakes.nullchecks defines function findByName() as pure -> searchName as String <- found as String: String() if searchName == "Alice" found: "Alice: Engineer" getPort() as pure <- port as Integer: 8080 defines program NullCheckDemo() stdout <- Stdout() // === GUARD EXPRESSION REPLACES NULL CHECK === // AI would write: result = findByName("Alice"); if (result != null) print(result) // EK9 way: guard expression if record <- findByName("Alice") stdout.println(`Found: ${record}`) if record <- findByName("Unknown") stdout.println("Found someone") else stdout.println("Not found, guard skipped the block") // === ? OPERATOR REPLACES NULL CHECK === // AI would write: if (name != null) print(name) // EK9 way: ? operator name <- String() if name? stdout.println("Has a name") else stdout.println("Name is unset (not null, just unset)") name: findByName("Steve") if name? stdout.println(`Name is set: ${name}`) // === GUARDED ASSIGNMENT REPLACES NULL COALESCING === // AI would write: host = host != null ? host : "localhost" // EK9 way: :=? guarded assignment host <- String() host :=? "localhost" stdout.println(`Host: ${host}`) host :=? "other" stdout.println(`Still: ${host}`) // === GUARD WITH FUNCTION RETURN === if port <- getPort() stdout.println(`Port: ${port}`)
Common mistakes
E01073 — EK9 has no null keyword. Use guard expressions with '<-' to check if a value is set and assign it in one step. See ek9 -h E01073 for details.
Incorrect:
if findByName("Alice") != null
Correct:
if record <- findByName("Alice")
E01073 — EK9 uses the ? operator to check if an object is set, not null comparisons. The ? operator returns Boolean. See ek9 -h E01073 for details.
Incorrect:
if name != null
Correct:
if name?
E01073 — EK9 uses the guarded assignment operator :=? which only assigns if the variable is currently unset. This replaces null coalescing patterns. See ek9 -h E01073 for details.
Incorrect:
host = host != null <- host : "localhost"
Correct:
host :=? "localhost"
Other ways to ask this
- Why does AI use 'if x != null' in EK9?
- How do I replace AI-generated null checks in EK9?
- What does EK9 use instead of null?
Coming from another language?
Java: null checks everywhere, NullPointerException is most common exception, Optional since Java 8. Python: 'if x is not None', AttributeError from None. JavaScript: null AND undefined, loose equality traps. Kotlin: nullable types String?, safe call ?. operator, Elvis ?:. Rust: Option<T> with match/if-let. Go: nil checks. EK9: NO null, tri-state model (absent/unset/set), ? operator checks isSet, guard expressions combine check and assignment, :=? guarded assignment for defaults.
Keywords: pitfall, common-error, unset, nil, check, migrate, hallucination, null-safe, isset, mistake, safe, null, ai, absent, set, none, tristate, guard, wrong