Why doesn't EK9 have switch fallthrough and how do I group cases?

← Control Flow · Ref: Q147

Switch fallthrough is one of the most dangerous features in programming. EK9 eliminates it entirely and provides a safer, clearer alternative.

THE FALLTHROUGH PROBLEM

In C, Java, and JavaScript, switch cases fall through to the next case by default. Forgetting a break statement causes silent execution of unintended code. CERT ranks this as the 7th most dangerous coding error. The bug is insidious because the code compiles and often appears to work until an edge case triggers the missing break.

A CLASSIC FALLTHROUGH BUG

In Java, this code silently assigns the wrong category:

  switch (code) {
    case 1: result = "admin";
    // missing break - falls through!
    case 2: result = "user";
    break;
  }

When code is 1, result becomes "user" instead of "admin". The compiler gives no warning. This pattern has caused countless production bugs.

EK9 SOLUTION: MULTIPLE VALUES PER CASE

EK9 uses comma-separated values in a single case clause:

  switch code
    case 1, 2, 3
      category: "low"
    case 4, 5
      category: "high"
    default
      category: "unknown"

Each case runs its body and stops. There is no fallthrough mechanism in the language.

SWITCH AS EXPRESSION

Switch can return a value directly:

  label <- switch priority
    <- rtn as String?
    case 1, 2
      rtn: "Low"
    case 3
      rtn: "Medium"
    case 4, 5
      rtn: "High"
    default
      rtn: "Unknown"

COMPARISON OPERATORS IN CASES

Cases can use comparison operators for range matching:

  switch score
    case >= 90
      grade: "A"
    case >= 80
      grade: "B"
    case >= 70
      grade: "C"
    default
      grade: "F"

ENUM SWITCHES

With enumerations you list the values, but a switch statement still needs 'default' even when every value is covered - it handles the unset value (E07320 without it):

  switch colour
    case Hue.Red
      label: "stop"
    case Hue.Amber
      label: "caution"
    case Hue.Green
      label: "go"
    default
      label: "unknown"

See Q63 for basic switch syntax. See Q68 for switch as expression. See Q69 for multiple case values. See Q70 for comparison operators in cases. See Q73 for enum exhaustiveness. See Q144 for the full control flow philosophy.

Example

defines module qa.flow.philosophy.nofallthrough

  defines type
    Hue
      Red
      Amber
      Green

  defines program

    NoFallthroughDemo()
      stdout <- Stdout()

      // === MULTIPLE VALUES PER CASE ===

      codes <- [1, 2, 3, 4, 5, 6]
      for code in codes
        category <- String()
        switch code
          case 1, 2, 3
            category: "low"
          case 4, 5
            category: "high"
          default
            category: "unknown"
        stdout.println(`Code ${code} -> ${category}`)

      // === SWITCH AS EXPRESSION ===

      priorities <- [1, 3, 5]
      for priority in priorities
        label <- switch priority
          <- rtn as String?
          case 1, 2
            rtn: "Low"
          case 3
            rtn: "Medium"
          case 4, 5
            rtn: "High"
          default
            rtn: "Unknown"
        stdout.println(`Priority ${priority}: ${label}`)

      // === COMPARISON OPERATORS IN CASES ===

      scores <- [95, 82, 71, 55]
      for score in scores
        grade <- String()
        switch score
          case >= 90
            grade: "A"
          case >= 80
            grade: "B"
          case >= 70
            grade: "C"
          default
            grade: "F"
        stdout.println(`Score ${score}: grade ${grade}`)

      // === ENUM SWITCH ===

      colours <- [Hue.Red, Hue.Amber, Hue.Green]
      for colour in colours
        meaning <- String()
        switch colour
          case Hue.Red
            meaning: "stop"
          case Hue.Amber
            meaning: "caution"
          case Hue.Green
            meaning: "go"
          default
            meaning: "unknown"
        stdout.println(`${colour} means ${meaning}`)

Common mistakes

E01070 — EK9 has no break statement. Each case clause is self-contained with no fallthrough. The break keyword does not exist in the language. See ek9 -h E01070 for details.

Incorrect:

case 1, 2, 3
            category: "low"
            break

Correct:

case 1, 2, 3
            category: "low"

E01072 — EK9 has no return statement. Switch expressions automatically return the declared variable's value. There is no need (and no way) to explicitly return from a program. See ek9 -h E01072 for details.

Incorrect:

return label

Correct:

stdout.println(`Priority ${priority}: ${label}`)

E07320 — A switch statement requires a default clause to handle unexpected values. Without it, the compiler reports E07320. This ensures every possible value is handled. Enum switches also require default, even with every value covered, because it handles the unset value (see Q73). See ek9 -h E07320 for details.

Incorrect:

//no default case

Correct:

default
            category: "unknown"
Other ways to ask this
  • How does EK9 prevent switch fallthrough bugs?
  • What is wrong with switch fallthrough in other languages?
  • How do I handle multiple values in one case without fallthrough in EK9?
  • How do comma-separated case values replace switch fallthrough in EK9?

Coming from another language?

Java: switch fallthrough by default, break required to prevent it, switch expressions with arrow syntax since Java 14 eliminate fallthrough. C/C++: switch fallthrough by default, break required, Clang and GCC warn but cannot prevent. JavaScript: switch fallthrough by default, break required. Python: match/case since 3.10 with no fallthrough, pipe operator for multiple values. Rust: match with no fallthrough, pipe operator for multiple patterns, exhaustive. Go: switch with no fallthrough by default (opposite of C), explicit fallthrough keyword if needed. Kotlin: when with no fallthrough, comma-separated values. Swift: switch with no fallthrough, comma-separated values, exhaustive. C#: switch with no fallthrough between non-empty cases. EK9: no fallthrough mechanism exists, comma-separated case values, comparison operators in cases, switch as expression, enum exhaustiveness.

Keywords: case, values, silent, danger, condition, expression, break, branch, flow, migrate, comma, multiple, fallthrough, bug, cert, exhaustive, control, switch, safety