Write me a pure function classifyTemperature that takes a Float celsius and returns a String label, declaring the return variable WITHOUT a default and proving the compiler that every branch of the if/else chain initialises it.
← Data Flow Safety · Ref: Q1249
EK9 has TWO valid patterns for satisfying the compiler's data flow analysis on a return variable: declare with a default value (Pattern 1), or declare without a default and assign in EVERY branch including a final else (Pattern 2). This file demonstrates Pattern 2.
PATTERN 2: NO DEFAULT, MANDATORY ELSE
classifyTemperature() as pure -> celsius as Float <- label as String? if celsius >= HOT_THRESHOLD label: "hot" else if celsius >= WARM_THRESHOLD label: "warm" else if celsius >= COOL_THRESHOLD label: "cool" else label: "cold"
The declaration 'label as String?' creates an UNSET return variable with no initial value. The compiler then requires that every reachable code path assigns 'label' before the function returns. Without the final 'else', a celsius below COOL_THRESHOLD would leave label uninitialised — and the compiler raises E08020.
WHY USE PATTERN 2 INSTEAD OF PATTERN 1
Pattern 2 is preferable when:
1. There is NO sensible default value for the return type.
2. You want the compiler to FORCE you to think about every case.
3. Adding a new branch should be a deliberate decision (no silent fallthrough).
Pattern 1 (default value, see Q1240) is preferable when:
1. There IS a sensible default that should apply to any unhandled case.
2. New branches add refinement to a baseline behaviour.
USAGE
stdout.println(`30C: ${classifyTemperature(30.0)}`) // hot stdout.println(`22C: ${classifyTemperature(22.0)}`) // warm stdout.println(`15C: ${classifyTemperature(15.0)}`) // cool stdout.println(`-5C: ${classifyTemperature(-5.0)}`) // cold
KEY POINT
Magic literals (HOT_THRESHOLD, WARM_THRESHOLD, COOL_THRESHOLD) are extracted into a 'defines constant' block to satisfy E11064. Comparing against bare literals is rejected by EK9's quality analysis.
See Q1240 for Pattern 1 (default value). See Q633 for branch initialisation rules. See Q632 for definition order.
Example
defines module qa.dataflow.temperatureclassify defines constant HOT_THRESHOLD <- 25.0 WARM_THRESHOLD <- 18.0 COOL_THRESHOLD <- 10.0 defines function classifyTemperature() as pure -> celsius as Float <- label as String? if celsius >= HOT_THRESHOLD label: "hot" else if celsius >= WARM_THRESHOLD label: "warm" else if celsius >= COOL_THRESHOLD label: "cool" else label: "cold" defines program TemperatureClassifyDemo() stdout <- Stdout() stdout.println(`30C: ${classifyTemperature(30.0)}`) stdout.println(`22C: ${classifyTemperature(22.0)}`) stdout.println(`15C: ${classifyTemperature(15.0)}`) stdout.println(`-5C: ${classifyTemperature(-5.0)}`)
Common mistakes
E08020 — Without a final else and without a default value at declaration, label is uninitialised when celsius is below WARM_THRESHOLD. Either provide a default at declaration (Pattern 1) or add the final else (Pattern 2). See ek9 -h E08020 for details.
Incorrect:
if celsius >= HOT_THRESHOLD label: "hot" else if celsius >= WARM_THRESHOLD label: "warm"
Correct:
if celsius >= HOT_THRESHOLD label: "hot" else if celsius >= WARM_THRESHOLD label: "warm" else if celsius >= COOL_THRESHOLD label: "cool"
Other ways to ask this
- Show me how to satisfy data flow analysis when there is no default value on the return variable.
- Create a function whose every branch must explicitly assign the return variable.
- Implement a temperature classifier that uses an explicit final else to satisfy initialisation analysis.
- Write a function with no default return where every branch covers initialisation.
Coming from another language?
Java: definite assignment requires every branch to assign — but allows null. Rust: every match arm must assign or use Option. Go: zero-value initialisation always works (but may hide bugs). Python: NameError at runtime. EK9: compile-time enforcement — either Pattern 1 (default) or Pattern 2 (else mandatory), no third option.
Keywords: explicit else, branch initialisation, data flow, no default, E08020, exhaustive, if else chain, return variable