Can I give an Optional a new value inside the 'if o?' block that checked it?
← Control Flow · Ref: Q1960
No. Inside the scope that proved an Optional, Result or Iterator safe to unwrap ('if o?', or the body of a guard such as 'while o :=? next()'), EVERY store to it is E08040 - an assignment statement, and a nested construct's pre-flow alike:
o <- Optional("Steve") if o? o := Optional("Other") // E08040 - the statement re-points o if o := Optional("Other") then o? // E08040 - so does a nested head stdout.println(o.get())
The safe scope promises that o.get() works. After the store, o holds the NEW value, which nothing checked: an empty one would throw 'No such element' at the next o.get().
WHAT TO DO INSTEAD
- Guard into a NEW variable: 'if replacement <- other()' - the replacement has its own proof.
- Re-point after the safe scope has ended: 'if name := nextName() then name?' below the 'if name?' block.
A CONSTRUCT'S OWN HEAD IS THE PROOF
'while current :=? nextName() then count < limit' fills current once, before the loop (a pre-flow always runs exactly once), and that guard is what makes current.get() safe in the loop. A while, for, switch or try marks its whole scope safe, head included, so the compiler judges the head against the scope AROUND the construct: it is an error only when an enclosing 'if current?' had already proven current safe.
Only a guard head ('<-', ':=?') proves anything by itself: 'if o := next() then ready' assigns blindly, so o.get() in its body is E08030 (Q1963) - write the check into the condition: 'then o? and ready'.
See Q84 for Optional's operations and Q86 for Result guards.
Example
defines module qa.flow.guard.safescope defines function firstName() <- rtn <- Optional("Steve") nextName() <- rtn <- Optional("Stephen") noName() <- rtn <- Optional() of String defines program GuardInSafeScopeDemo() stdout <- Stdout() name <- firstName() stdout.println(`before: name set=${name?}`) if name? stdout.println("checked: " + name.get()) if replacement <- nextName() stdout.println("replacement: " + replacement.get()) alias <- noName() alias := nextName() moved <- alias? stdout.println(`moved=${moved} alias set=${alias?}`) stdout.println("inside: name=" + name.get()) if name := nextName() then name? stdout.println("re-pointed: " + name.get()) count <- 0 limit <- 2 current <- noName() while current :=? nextName() then count < limit stdout.println("loop: " + current.get()) count++ stdout.println("Done")
Common mistakes
E08040 — Inside 'if name?' the name is proven safe to unwrap, and the inner head's ':=' always stores its value into name, so the code after the inner if would unwrap a value nothing checked (an empty one throws 'No such element'). Guard into a NEW variable instead. See ek9 -h E08040 for details.
Incorrect:
if name := nextName() then name? stdout.println("replacement: " + name.get())
Correct:
if replacement <- nextName() stdout.println("replacement: " + replacement.get())
E08040 — An assignment statement is a store too. Re-pointing name inside the scope that checked it is E08040; assign a different variable. See ek9 -h E08040 for details.
Incorrect:
name := nextName()
Correct:
alias := nextName()
Other ways to ask this
- Why is 'if o := other() then o?' inside 'if o?' error E08040?
- Why can't I re-point a checked Optional inside its safe block?
- Is 'o := other()' allowed inside a safe access block?
- Why does a while loop's own 'o :=? next()' head not count as reassignment?
- How do I try a replacement Optional inside a block where the first one was checked?
Coming from another language?
Kotlin: a smart cast is silently lost when a var is reassigned; the error appears later, at the unchecked use. Rust: 'if let Some(v) = o' binds a separate value and 'o' cannot be reassigned while borrowed. Swift: 'if let' copies, so the original can change without affecting the binding. EK9 unwraps the original variable directly, so it rejects the store that would break the proof - an assignment statement or a nested construct's head.
Keywords: safe access, optional, while, reassignment, re-point, E08040, pre-flow, if o?, guard