E08030: has not been checked before access
What went wrong
You're accessing a method on Optional, Result, or Iterator that requires a set-check BEFORE access, but the compiler cannot verify safety. Check and access must be in the SAME syntactic scope.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 993 (The compiler reports E08030 on my discount lookup. What ...)
- ek9 -q 163 (How do I safely unwrap an Optional value?)
- ek9 -q 86 (How do Result guard patterns and ternary access work?)
- ek9 -q 47 (How does the Optional type work in EK9?)
- ek9 -q 84 (What operations does Optional support in EK9?)
- ek9 -q 48 (How does the Result type work in EK9?)
- ek9 -q 1379 (Why can't I call get() in a do-while body when the traili...)
Safe patterns
Each of these compiles:
//Inside the block the check protects if o? rtn += o.get() //isOk() guards ok() if r.isOk() rtn += r.ok() //A guard checks implicitly if found <- maybeCount() rtn += found.get() //hasNext() guards next() if iter <- o.iterator() then iter.hasNext() rtn += iter.next() //A top-level 'and' conjunct proves it if checked := maybeCount() then checked? and (rtn < limit) rtn += checked.get() //An earlier conjunct protects a later one if o? and o.get() > limit rtn += o.get()
Unsafe patterns
Each of these is this error:
//A copy of the check is not a guard hasValue <- o? if hasValue rtn += o.get() //No protection at all rtn += o.get() //A '?' under 'or', 'not' or a call argument proves nothing if (o? and first) or (o? and second) rtn += o.get() //The access runs BEFORE its check if o.get() > limit and o? rtn += 1
Rationale
Storing the check result in a variable breaks the guarantee because the original variable could be reassigned between check and access.
Safe alternatives
For Optional:
- o.getOrDefault("fallback")
- o.whenPresent(consumer)
For Result:
- r.okOrDefault("fallback")
- r.whenOk(consumer)
For Iterator:
- while iter <- x.iterator() then iter.hasNext()
How to fix it
- Use if/guard pattern that keeps check and access together
- Or use getOrDefault/whenPresent methods
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E08030: has not been checked before access
#!ek9 defines module error.e08030.bad defines function nameOf() -> maybe as Optional of String <- rtn as String: "nobody" rtn: maybe.get() unsafeForms() -> o as Optional of Integer first as Boolean second as Boolean limit as Integer <- rtn as Integer: 0 //A copy of the check is not a guard hasValue <- o? if hasValue rtn += o.get() //No protection at all rtn += o.get() //A '?' under 'or', 'not' or a call argument proves nothing if (o? and first) or (o? and second) rtn += o.get() //The access runs BEFORE its check if o.get() > limit and o? rtn += 1
Fixed: Check the Optional with ? on the path to each get()
#!ek9 defines module error.e08030.good.fix defines function nameOf() -> maybe as Optional of String <- rtn as String: "nobody" if maybe? rtn: maybe.get() unsafeForms() -> o as Optional of Integer first as Boolean second as Boolean limit as Integer <- rtn as Integer: 0 //A copy of the check is not a guard if o? rtn += o.get() //No protection at all if o? rtn += o.get() //A '?' under 'or', 'not' or a call argument proves nothing if o? and (first or second) rtn += o.get() //The access runs BEFORE its check if o? and o.get() > limit rtn += 1
Fixed: Check that it is set first
#!ek9 defines module error.e08030.good defines function nameOf() -> maybe as Optional of String <- rtn as String: "nobody" if maybe? rtn: maybe.get()
Fixed: Every form that checks before it reads, in the same construct
#!ek9 defines module error.e08030.good.forms defines function maybeCount() <- rtn as Optional of Integer: Optional(2) safeForms() -> o as Optional of Integer r as Result of (Integer, String) limit as Integer <- rtn as Integer: 0 checked <- Optional() of Integer //Inside the block the check protects if o? rtn += o.get() //isOk() guards ok() if r.isOk() rtn += r.ok() //A guard checks implicitly if found <- maybeCount() rtn += found.get() //hasNext() guards next() if iter <- o.iterator() then iter.hasNext() rtn += iter.next() //A top-level 'and' conjunct proves it if checked := maybeCount() then checked? and (rtn < limit) rtn += checked.get() //An earlier conjunct protects a later one if o? and o.get() > limit rtn += o.get()
Questions and answers
These Q&A entries show E08030 and its fix:
- Q47: How does the Optional type work in EK9?
- Q48: How does the Result type work in EK9?
- Q84: What operations does Optional support in EK9?
- Q86: How do Result guard patterns and ternary access work?
- Q163: How do I safely unwrap an Optional value?
- Q165: Why don't Dict and List have a .get() method in EK9?
- Q166: What is the consistent safe-access pattern across all EK9 types?
- Q259: How does EK9's Result type differ from other languages?
- Q993: The compiler reports E08030 on my discount lookup. What is wrong and how do I fix it?
- Q1364: How do I read and write CSV in EK9?
- Q1372: How do I run a callback over a collection that is held inside an Optional or Result?
- Q1379: Why can't I call get() in a do-while body when the trailing while condition checks the Optional?
- Q1963: Why can't I call get() on an Optional assigned with ':=' in an if head?