Can I use a guard (including '?=') inside a switch or loop expression in EK9?

← Control Flow · Ref: Q837

Yes. A body-skipping guard ('<-' declaration, '?=' guarded assignment, ':=?' assign-if-unset) works in an expression-form switch/for/while/do-while/try, just as in statement form. The guard gates the whole construct: if the guarded value is unset the body is skipped, and the left-hand side takes the returning variable's INITIAL value - 'the initialiser is the guard's else'.

BECAUSE OF THAT, THE RETURN MUST BE INITIALISED

Declare the return with an initial value ('<- rtn as T: default'). If you declare it uninitialised ('<- rtn as T?') and set it only inside the (skippable) body, the compiler rejects it with E08050 RETURN_NOT_ALWAYS_INITIALISED, because the skip path would leave the LHS unset.

THIS EXAMPLE

A switch expression with a '?=' guard and an initialised return. The guard sets 'temperature', the switch runs, and 'resultText' gets a case value; had the guard left 'temperature' unset, 'resultText' would be the initial "Unknown".

See Q759 for guard patterns. See Q69 for multi-case switch.

Example

defines module qa.controlflow.guard.expression

  defines function

    currentTemperature() as pure
      -> country as String
      <- temperature as Integer?

      if country == "GB"
        temperature :=? 18
      else if country == "DE"
        temperature :=? 35
      else
        temperature :=? 25

  defines program

    GuardDemo()
      stdout <- Stdout()

      //Valid: a '?=' guard in a switch expression. The guard gates the switch; if 'temperature' were left
      //unset the body would be skipped and 'resultText' would take the return's initial value ("Unknown").
      temperature as Integer?
      resultText <- switch temperature ?= currentTemperature("GB") with temperature
        <- result as String: "Unknown"
        case < 12
          result: "Cold"
        case < 25
          result: "Moderate"
        default
          result: "Warm"

      stdout.println(resultText)

Common mistakes

E08050 — In an expression form, a guard can skip the body, so the return must be initialised at declaration. Give it a default ('<- result as String: "Unknown"'); an uninitialised '<- result as String?' set only in the body is E08050 RETURN_NOT_ALWAYS_INITIALISED.

Incorrect:

        <- result as String?

Correct:

        <- result as String: "Unknown"
Other ways to ask this
  • Do guards work in switch/for/while/try expressions?
  • What does 'result <- switch temp ?= getValue() with temp' do?
  • Why does a guard in an expression need an initialised return (E08050)?

Coming from another language?

Kotlin 'when' and Rust 'match' are expressions but have no guard-gating pre-flow. EK9 unifies it: the same guard syntax works in statement AND expression forms, and the mandatory return initialiser is the value the LHS receives when the guard skips.

Keywords: conditional, switch, E08050, guarded assignment, expression, initialised return, guard