How does exhaustive enum switch work?
← Control Flow · Ref: Q73
When you switch over an enumeration and use direct constant references in cases, EK9's compiler verifies that ALL enumeration values are covered. Missing a value is a compile-time error.
EXHAUSTIVE ENUM SWITCH
All enum values must appear in cases:
switch heading case Direction.North label: "going north" case Direction.South label: "going south" case Direction.East label: "going east" case Direction.West label: "going west" default label: "direction not set"
The compiler checks that North, South, East, and West are ALL present. Missing one is a compile error.
DEFAULT IS REQUIRED
Even with all enum values listed, a 'default' block is required. This handles the case where the enum variable is unset (EK9's tri-state semantics mean a variable can be present but have no value).
COMPILE-TIME SAFETY
If you later add a new value to the enum (say Direction.NorthWest), the compiler will flag every exhaustive switch that is now incomplete. This forces you to handle the new value everywhere, preventing silent bugs.
NON-EXHAUSTIVE OPT-OUT
Use the equality operator '==' to disable exhaustive checking:
switch heading case == Direction.North label: "going north" default label: "not north"
With '== Direction.North' instead of 'Direction.North', the compiler treats this as a comparison, not an exhaustive match. You can handle only the values you care about.
MULTIPLE ENUM VALUES PER CASE
Group enum values with commas:
switch heading case Direction.North, Direction.South axis: "vertical" case Direction.East, Direction.West axis: "horizontal" default axis: "none"
This is exhaustive: all four values are covered across the two cases.
EXPRESSION FORM
Exhaustive enum switch works in expression form:
label <- switch heading <- rtn as String? case Direction.North rtn: "N" ... default rtn: "?"
See Q63 for basic switch. See Q68 for switch expression form. See Q69 for multiple values per case. See Q99 for creating enumerations. See Q100 for how EK9 enums differ from Java enums. See Q226 for enum bug prevention.
Example
defines module qa.flow.switch.exhaustive defines type Direction North, South, East, West defines function describeDirection() as pure -> heading as Direction <- description <- String() //Exhaustive: all four values must be present switch heading case Direction.North description: "heading north" case Direction.South description: "heading south" case Direction.East description: "heading east" case Direction.West description: "heading west" default description: "direction not set" describeAxis() as pure -> heading as Direction <- axis <- String() //Exhaustive with grouped values switch heading case Direction.North, Direction.South axis: "vertical" case Direction.East, Direction.West axis: "horizontal" default axis: "none" isNorth() as pure -> heading as Direction <- northward <- String() //Non-exhaustive: uses == operator to opt out switch heading case == Direction.North northward: "yes, heading north" default northward: "not heading north" defines program EnumSwitchDemo() stdout <- Stdout() // === EXHAUSTIVE SWITCH === directions <- [Direction.North, Direction.South, Direction.East, Direction.West] for heading in directions stdout.println(describeDirection(heading)) // === GROUPED ENUM VALUES === for heading in directions stdout.println(`${describeDirection(heading)} is on ${describeAxis(heading)} axis`) // === NON-EXHAUSTIVE WITH == === for heading in directions stdout.println(isNorth(heading)) // === EXPRESSION FORM === testHeading <- Direction.East symbol <- switch testHeading <- rtn as String? case Direction.North rtn: "N" case Direction.South rtn: "S" case Direction.East rtn: "E" case Direction.West rtn: "W" default rtn: "?" stdout.println(`Direction symbol: ${symbol}`)
Common mistakes
E01070 — EK9 has no break statement. Exhaustive enum switch cases are self-contained with no fallthrough. See ek9 -h E01070 for details.
Incorrect:
switch heading case Direction.North description: "heading north" break
Correct:
switch heading case Direction.North description: "heading north"
E01072 — EK9 has no return statement. Functions use declared return variables. The compiler verifies all paths initialise the return variable. See ek9 -h E01072 for details.
Incorrect:
describeDirection() as pure -> heading as Direction switch heading case Direction.North return "heading north"
Correct:
describeDirection() as pure -> heading as Direction <- description <- String()
Other ways to ask this
- Does EK9 check that all enum values are handled in a switch?
- How do I switch over an enumeration in EK9?
- What happens if I miss an enum value in a switch?
Coming from another language?
Rust: match on enum is exhaustive, compiler error if arm missing, _ for wildcard. Kotlin: when on sealed class or enum is exhaustive when used as expression, else required. Java: switch on enum since Java 5, exhaustive checking only with switch expressions since Java 21 with sealed types. Python: match/case has no exhaustive checking for enums. Go: no enum type (iota constants), no exhaustive checking. C/C++: switch on enum has optional compiler warnings for missing cases (-Wswitch), not enforced. C#: switch on enum not exhaustive by default, Roslyn analyzers can check. Swift: switch on enum is exhaustive, compiler error if case missing, @unknown default for future values. EK9: switch on enum is exhaustive when using direct constant references, use == operator to opt out, default always required for unset handling.
Keywords: flow, compiler, branch, control, condition, cover, complete, enum, switch, migrate, enumeration, missing, check, exhaustive