Walk me through using :=? on an Integer retry counter so that the counter only gets initialised on the first call and is preserved on subsequent calls.
← Operators and Expressions · Ref: Q1264
The :=? guarded assignment operator works on any type, including Integer. It assigns the right-hand value ONLY when the target is currently unset. This is exactly what you want for 'initialise once, never overwrite' patterns like retry counters, lazy caches, and configuration defaults.
WORKED EXAMPLE: RETRY COUNTER
retryCount as Integer: Integer() // unset
// First call: assigns 0 because retryCount was unset retryCount :=? 0 stdout.println(`first :=? 0 -> ${retryCount}`)
// Second call: SKIPPED because retryCount is now set to 0 retryCount :=? 99 stdout.println(`second :=? 99 -> ${retryCount}`)
The second :=? does NOT change the value, even though 99 is different from 0. The operator only checks 'is the target unset?', not 'is the value different?'.
INCREMENTING ON TOP OF GUARDED INIT
A common pattern is to guard the initial value, then mutate freely afterwards:
attempts as Integer: Integer() attempts :=? 0 // initialise once attempts++ // 1 attempts++ // 2 attempts++ // 3 stdout.println(`attempts: ${attempts}`)
The first :=? guarantees the counter starts from 0 even if the variable was created without a default. After that, ++ takes over.
WHY THIS IS SAFER THAN PLAIN :=
Using := blindly would overwrite the existing count and lose progress:
retryCount: 0 // Always overwrites — bad in restart-safe code retryCount :=? 0 // Only sets if unset — safe to call multiple times
For any value that should be 'set once and stay', :=? is the right operator.
See Q1263 for String guarded assignment. See Q1265 for Date. See Q1266 for custom record. See Q1226 for the contrast between :=? and <?.
Example
defines module qa.operators.guardedassigninteger defines program GuardedAssignIntegerDemo() stdout <- Stdout() retryCount as Integer: Integer() retryCount :=? 0 stdout.println(`first :=? 0 -> ${retryCount}`) retryCount :=? 99 stdout.println(`second :=? 99 -> ${retryCount}`) attempts as Integer: Integer() attempts :=? 0 attempts++ attempts++ attempts++ stdout.println(`attempts after ++: ${attempts}`)
Common mistakes
E50060 — Integer does not have a guardedSet method. The :=? operator is the correct way to perform guarded assignment — it assigns only when the target is unset. See ek9 -h E50060 for details.
Incorrect:
retryCount.guardedSet(0)
Correct:
retryCount :=? 0
Other ways to ask this
- How do I initialise an Integer counter only once using :=?
- Show me a worked example of guarded assignment for a retry counter.
- Initialise an Integer to a default only when it has not been set.
- How does :=? behave on Integer values that may already be set?
Coming from another language?
Java: if (count == null) count = 0; — needs Integer wrapper, not int. Kotlin: count = count ?: 0. Rust: let count = count.unwrap_or(0); — but this rebinds, not modifies. Python: count = count if count is not None else 0. EK9: count :=? 0 — single operator, in-place, idempotent.
Keywords: retry counter, :=?, initialise once, guarded assignment, Integer, lazy init, default value