How does switch/case work in EK9?

← Control Flow · Ref: Q63

EK9's switch matches a value against multiple cases. It looks familiar but has important differences from other languages: no break statements needed, no fallthrough between cases, and the ability to match multiple values per case.

BASIC SWITCH

Match a value against literal cases:

  switch status
    case 1
      message: "active"
    case 2
      message: "inactive"
    case 3
      message: "pending"
    default
      message: "unknown"

Each case runs its body and stops. There is no fallthrough and no break keyword.

STRING MATCHING

Switch works with any type that supports equality:

  switch command
    case "start"
      doStart()
    case "stop"
      doStop()
    default
      showHelp()

DEFAULT CASE

The default block handles any value not matched by a case. It is optional but recommended for safety:

  switch direction
    case "north"
      y: y + 1
    case "south"
      y: y - 1
    default
      stdout.println("Unhandled direction")

NO BREAK NEEDED

In Java and C, forgetting 'break' causes fallthrough bugs. EK9 eliminates this entirely. Each case is self-contained. There is no break keyword in EK9 (see Q144 for why).

NO FALLTHROUGH

If you need multiple values to execute the same code, use comma-separated case values instead of fallthrough (see Q69):

  switch day
    case "Saturday", "Sunday"
      type: "weekend"
    default
      type: "weekday"

MORE POWER

Switch in EK9 goes far beyond simple literal matching:
- Return values as an expression (see Q68)
- Multiple values per case (see Q69)
- Comparison operators like case < 12 (see Q70)
- Pattern matching with regex (see Q71)
- Alternative keywords given/when (see Q72)
- Exhaustive enum matching (see Q73)
- Guard variables for safe access (see Q74)

See Q61 for if/else as an alternative. See Q62 for when if/else-if chains might be better. See Q68 for switch expression. See Q73 for enum switch.

Example

defines module qa.flow.branching

  defines function

    supplyStatusCode()
      <- rtn <- 2

    supplyCommand()
      <- rtn <- "greet"

    supplyDay()
      <- rtn <- "Saturday"

  defines program

    SwitchDemo()
      stdout <- Stdout()

      // === BASIC SWITCH WITH INTEGERS ===

      statusCode <- supplyStatusCode()
      message <- String()
      switch statusCode
        case 1
          message: "active"
        case 2
          message: "inactive"
        case 3
          message: "pending"
        default
          message: "unknown"
      stdout.println(`Status ${statusCode}: ${message}`)

      // === SWITCH WITH STRINGS ===

      command <- supplyCommand()
      switch command
        case "greet"
          stdout.println("Hello!")
        case "farewell"
          stdout.println("Goodbye!")
        default
          stdout.println("Unknown command")

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

      day <- supplyDay()
      dayType <- String()
      switch day
        case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"
          dayType: "weekday"
        case "Saturday", "Sunday"
          dayType: "weekend"
        default
          dayType: "invalid"
      stdout.println(`${day} is a ${dayType}`)

      // === SWITCH IN A LOOP ===

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

Common mistakes

E01070 — EK9 has no break statement. Switch cases do not fall through, so break is unnecessary and does not exist in the grammar. Each case is self-contained. See ek9 -h E01070 for details.

Incorrect:

switch statusCode
        case 1
          message: "active"
          break
        case 2
          message: "inactive"
          break

Correct:

switch statusCode
        case 1
          message: "active"
        case 2
          message: "inactive"

E01072 — EK9 has no return statement. In a program, execution flows naturally to the end. In functions, use a declared return variable instead. See ek9 -h E01072 for details.

Incorrect:

switch command
        case "greet"
          stdout.println("Hello!")
          return
        case "farewell"
          stdout.println("Goodbye!")
          return

Correct:

switch command
        case "greet"
          stdout.println("Hello!")
        case "farewell"
          stdout.println("Goodbye!")
Other ways to ask this
  • What is EK9's equivalent of switch or match?
  • How do I match a value against multiple options in EK9?
  • How does case matching work in EK9?

Coming from another language?

Java: switch with break required (fallthrough by default), switch expressions since Java 14 with arrow syntax. Python: match/case since 3.10, structural pattern matching (different from simple value matching). Rust: match is exhaustive, is an expression, pattern matching with destructuring. Go: switch with no fallthrough by default (opposite of C/Java), implicit break. C/C++: switch with break required, fallthrough by default, major bug source. Kotlin: when expression replaces switch, no fallthrough, exhaustive with sealed classes. C#: switch with break required, switch expressions since C# 8. JavaScript: switch with break required, fallthrough by default. Swift: switch is exhaustive, no fallthrough, pattern matching. EK9: switch with no break keyword, no fallthrough, comma-separated multi-case values, comparison operators in cases, given/when alternative keywords.

Keywords: match, branch, control, flow, condition, fallthrough, break, default, switch, migrate, given, value, literal, case