Why must a switch on an enumeration cover all values?

← Control Flow · Ref: Q792

A switch on an enumeration must do BOTH: cover every declared value AND provide a default. These are two separate requirements, enforced by two different errors — a default does NOT excuse you from listing the cases.

WHY EVERY VALUE MUST BE COVERED (E07310)

If you add a new value to the enum later (e.g. PURPLE), the compiler flags every switch that doesn't handle it.

WHY A DEFAULT IS ALSO REQUIRED (E07320 statement / E07330 expression)
EK9 enumerations are tri-state like every other EK9 type: an enumeration variable can exist but be UNSET. 'Color()' is unset, and 'Color("Purple")' is also unset because the text matches no declared value — EK9 returns an unset Color rather than throwing. No 'case' can ever match the unset state, so 'default' is the branch that handles it.

This is why the default does not weaken exhaustiveness: the cases stay exhaustive over the DECLARED values, and the default covers 'no value at all'.

THIS EXAMPLE

describe() handles all three colours and has a default returning "unset" — the branch taken by describe(Color()).

See Q73 for exhaustive enum switch. See Q87 for enumerations. See Q788 for switch default required.

Example

defines module qa.controlflow.enumswitch

  defines type

    Color
      Red,
      Green,
      Blue

  defines function

    describe() as pure
      -> shade as Color
      <- rtn as String: "unknown"

      switch shade
        case Color.Red
          rtn: "red"
        case Color.Green
          rtn: "green"
        case Color.Blue
          rtn: "blue"
        default
          rtn: "unset"

  defines program

    ShowColors()
      stdout <- Stdout()
      stdout.println(describe(Color.Red))
      stdout.println(describe(Color.Blue))

      //An enumeration is tri-state, so a Color can exist while holding no value.
      //No 'case' can match that - which is why 'default' is mandatory. Both print "unset".
      stdout.println(describe(Color()))
      stdout.println(describe(Color("Purple")))

Common mistakes

E07310 — The switch on Color only handles Red and Green — Blue is missing, so E07310 fires. Add 'case Color.Blue'. Note the existing 'default' does NOT satisfy this: the default is separately mandatory (E07320/E07330) because it handles the UNSET enumeration state, not the missing case. See ek9 -h E07310 for details.

Incorrect:

        case Color.Green
          rtn: "green"

Correct:

        case Color.Green
          rtn: "green"
        case Color.Blue
          rtn: "blue"
Other ways to ask this
  • What triggers E07310 not all enumerated values present in switch?
  • How do I make an exhaustive enum switch in EK9?
  • Do I need a default when switching on an enum?

Coming from another language?

Java: exhaustive switch on sealed types (Java 21+). Python: match/case has no exhaustiveness check. Rust: match on enum must be exhaustive (compiler enforced). Kotlin: when on sealed class must be exhaustive. Go: no exhaustiveness check on switch. EK9: compiler enforces all declared enum values covered AND a default — unlike Rust/Kotlin, an EK9 enumeration is tri-state and can be UNSET, and the default is the branch that handles that state.

Keywords: default, tri-state, exhaustive, E07330, all values, unset, missing, E07320, enum, case, E07310, switch