How do I accumulate partial results without break?
← Control Flow Without break/continue/return · Ref: Q286
In Java you write: result = null; for (...) { if (match) { result = x; break; } }. In EK9, the :=? guarded assignment operator is purpose-built for first-assignment-wins.
THE PROBLEM
You want to find a value from the first matching source in priority order. Other languages use a loop with break-on-found. The break is the mechanism for stopping after the first match.
PATTERN 1: PRIORITY CHAIN WITH :=?
Try each source in priority order. The first one that sets the value wins:
resolveConfig()
-> envSetting as String, fileSetting as String, hardcoded as String
<- setting as String: String()
setting :=? envSetting
setting :=? fileSetting
setting :=? hardcoded
The :=? operator only assigns when the target is unset. Once setting gets a value from envSetting, the subsequent assignments are no-ops. No loop, no break.
PATTERN 2: STREAM COLLECT FOR BATCH
When accumulating ALL matching items (not first-wins), use stream collect:
matches <- cat items | filter by isValid | collect as List of String
No break needed because you want everything that matches.
PATTERN 3: SWITCH WITH DECLARED RETURN
When dispatching on a single value, switch with a declared return replaces break-based dispatch:
classify() as pure -> score as Integer <- label as String: "average" switch score case >= 90 label: "excellent" case >= 70 label: "good" case < 40 label: "poor" default label: "average"
KEY INSIGHT
The :=? operator IS the break-on-found replacement. It was designed specifically for the first-assignment-wins pattern. No loops needed for priority lookup. No break needed for accumulation.
See Q50 for guarded assignment. See Q29 for :=? semantics. See Q79 for guarded assignment details. See Q122 for collect.
Example
defines module qa.without.accumulate defines function // Pattern 1: Priority chain resolveConfig() -> envSetting as String fileSetting as String hardcoded as String <- setting as String: String() setting :=? envSetting setting :=? fileSetting setting :=? hardcoded isValid() as pure -> item as String <- valid as Boolean? minValidLength <- 3 valid: length item > minValidLength // Pattern 3: Switch with declared return classify() as pure -> score as Integer <- label as String: "average" switch score case >= 90 label: "excellent" case >= 70 label: "good" case < 40 label: "poor" default label: "average" defines program AccumulateDemo() stdout <- Stdout() // === PATTERN 1: PRIORITY CHAIN === defaultSetting <- "hardcoded" // Environment wins (first non-empty source) envResult <- resolveConfig("from-env", "from-file", defaultSetting) stdout.println(`Priority (env set): ${envResult}`) // File wins when env is unset fileResult <- resolveConfig(String(), "from-file", defaultSetting) stdout.println(`Priority (env unset): ${fileResult}`) // Hardcoded wins when both are unset defaultResult <- resolveConfig(String(), String(), defaultSetting) stdout.println(`Priority (both unset): ${defaultResult}`) // === PATTERN 2: STREAM COLLECT === items <- ["hi", "apple", "banana", "ok", "cherry"] allValid <- cat items | filter by isValid | collect as List of String stdout.println(`All valid items: ${allValid}`) // === PATTERN 3: SWITCH DISPATCH === scores <- [95, 72, 55, 38] for score in scores stdout.println(`Score ${score}: ${classify(score)}`) // === FIRST-WINS IN A LOOP === names <- ["", "", "Alice", "Bob"] chosen <- String() for name in names if length name > 0 chosen :=? name stdout.println(`First non-empty name: ${chosen}`)
Common mistakes
E50001 — Renaming the variable means later references to 'envResult' become unresolved, triggering E50001. Variable names must be consistent. See ek9 -h E50001 for details.
Incorrect:
envResultXYZ <- resolveConfig("from-env", "from-file", defaultSetting)
Correct:
envResult <- resolveConfig("from-env", "from-file", defaultSetting)
Other ways to ask this
- How do I build a result from the first matching condition without break in EK9?
- How does guarded assignment replace break-on-found in EK9?
- How do I implement first-wins priority lookup in EK9?
Coming from another language?
Java: result = null; for (...) { if (match) { result = x; break; } } or Optional.orElse chain. Python: result = None; for ...: if match: result = x; break, or next() with generator. Rust: iter().find() or match with first arm. Go: for loop with break on found. Kotlin: firstOrNull() or generateSequence. JavaScript: find() or for loop with break. EK9: :=? guarded assignment for priority chain, stream collect for batch, switch for dispatch.
Keywords: error, lookup, null-safe, guarded, first, no-return, wins, build, collect, migrate, assignment, alternative, safe, result, isset, partial, config, accumulate, no-break, priority, ok