How do := and :=? work differently as guard operators in EK9 control flow?
← Control Flow · Ref: Q1025
The key difference is WHAT gets checked and WHEN the expression evaluates.
:= (BLIND ASSIGNMENT)
Always evaluates the expression. Always assigns. No isSet checks.
if count := getCount() with count > 0 process(count)
getCount() is called unconditionally. count is assigned unconditionally. The 'with' condition is the only gate.
:=? (ASSIGNMENT IF UNSET)
First checks if the target variable is already SET. Only evaluates the expression if the target is UNSET. Then checks the result before assigning.
if cache :=? expensiveCompute() with cache > threshold useCache(cache)
If cache already has a value, expensiveCompute() is NEVER called. This is lazy evaluation.
WHEN TO USE :=
- Fetching fresh data every time (sensor readings, API polls) - The value changes between calls and you want the latest - Combined with 'with' condition for validation
WHEN TO USE :=?
- Caching: avoid re-computing if already have a result - Configuration defaults: try sources in priority order - First-match: assign from first source that provides a value - Loop with lazy init: only initialize on first iteration
See Q1023 for all three operators compared. See Q79 for :=? standalone. See Q1024 for ?= protection.
Example
defines module qa.controlflow.assign.vs.assignifunset defines function fetchFreshData() <- rtn as Integer? rtn: 10 expensiveCompute() <- rtn as Integer? rtn: 99 defines program AssignVsAssignIfUnsetDemo() stdout <- Stdout() minCounter <- 5 threshold <- 50 // === := BLIND ASSIGNMENT in IF === // Always evaluates, always assigns. counter <- Integer() if counter := fetchFreshData() with counter > minCounter stdout.println(":= fetched and condition met: " + $counter) // === :=? ASSIGNMENT IF UNSET in IF === // cache starts unset -> expensiveCompute() IS called cache <- Integer() if cache :=? expensiveCompute() with cache > threshold stdout.println(":=? computed (was unset): " + $cache) // cache is now set to 99 -> expensiveCompute() is NOT called again if cache :=? expensiveCompute() with cache > threshold stdout.println(":=? skipped compute (already set): " + $cache) // === := ALWAYS RE-FETCHES (contrast with :=?) === // counter already has value 10, but := overwrites it if counter := fetchFreshData() with counter > minCounter stdout.println(":= re-fetched (always evaluates): " + $counter)
Common mistakes
E01072 — 'return' does not exist in EK9 — declare the return value with '<-' and assign it with 'rtn:'. See ek9 -h E01072 for details.
Incorrect:
return 10
Correct:
rtn: 10
Other ways to ask this
- When should I use := vs :=? in a while loop or if statement?
- What is the difference between blind assignment and assignment-if-unset in guards?
- How does :=? avoid re-evaluation in EK9 control flow?
- Show me := vs :=? in if and while in EK9
Coming from another language?
Java: ':=' is like simple assignment 'x = expr;'. ':=?' requires 'if (x == null || !x.isSet()) { var temp = expr(); if (temp != null && temp.isSet()) x = temp; }' — 4 lines vs 1. Go: No ':=?' equivalent. Must write 'if x == nil { x = compute() }'. Python: No direct equivalent. 'x = x or compute()' breaks for falsy values.
Keywords: control, evaluation, blind, operator, conditional, assign, if, lazy, while, flow, guard, cache, unset, compare, default