Can I use a '<-' guard's variable in the else block of the same if?

← Control Flow · Ref: Q2002

Not to read it before you assign it. Every later 'else if' and 'else' of an 'if name <- lookup()' chain runs BECAUSE the guard failed - name was unset - so reading name there finds nothing: that read is E08270, and testing it with 'name?' is always false (E08089).

A WRITE stays legal, and a read after the write is fine. Re-point it in a later head and check it: 'else if name := lookup("fallback") then name?'.

The rule covers a guard that is the whole condition. With a 'then' condition, or over a Boolean (unset OR false), the later block may see a value, so it is not checked.

See Q74 for the guard in an if and Q2001 for guards over a Boolean.

Example

defines module qa.controlflow.guardvariableinelse

  defines function

    lookup()
      -> key as String
      <- rtn as String: key

  defines program

    GuardVariableInElse()
      stdout <- Stdout()

      if found <- lookup(String())
        stdout.println(`found ${found}`)
      else
        stdout.println("nothing found")

      if name <- lookup(String())
        stdout.println(`name ${name}`)
      else if name := lookup("fallback") then name?
        stdout.println(`using ${name}`)
      else
        stdout.println("no name at all")

Common mistakes

E08270 — The else runs because 'found' was unset, so reading it there finds nothing. Use it inside the guarded block, or assign it first. See ek9 -h E08270 for details.

Incorrect:

        stdout.println(`nothing found for ${found}`)

Correct:

        stdout.println("nothing found")

E08089 — In a later block of the chain the guard's variable is always unset, so checking it is always false. Re-point it first: 'else if name := lookup(...) then name?'. See ek9 -h E08089 for details.

Incorrect:

      else if name?

Correct:

      else if name := lookup("fallback") then name?
Other ways to ask this
  • What does E08270 mean?
  • Why is reading the guard variable in the else an error?
  • How do I give a guard variable a value in a later else if?
  • Why is 'else if name?' always false after 'if name <- lookup()'?

Coming from another language?

Swift: 'if let name = lookup() { } else { }' - name is not even in scope in the else. Kotlin: 'lookup()?.let { } ?: run { }' - same. EK9 keeps the variable in scope for the whole chain so a later head can assign it, and rejects the reads that can only find nothing.

Keywords: declaration guard, else if, guard, scope, E08089, else, unset, E08270