E08270: a '<-' guard's variable is always unset in the later 'else if' and 'else' blocks of its 'if' - they run because it was unset - so this read finds nothing; use it inside the guarded block, or assign it a new value first

Category: E08xxx Pre-IR checks (flow analysis) · Reported in phase: PRE_IR_CHECKS · Classification: GUARD_VARIABLE_READ_WHERE_UNSET · All error codes

What went wrong

A '<-' guard's variable is read in a later 'else if' or 'else' block of its own 'if', before anything assigns it there. 'if found <- fetch()' declares 'found' for the whole if/else chain, and every later block runs only because 'found' was unset - so the read can only find nothing (the [EXAMPLE] section below prints 'found' in the 'else', where it is always unset).

Only a guard that is the whole condition is reported. With a 'then'/'with' condition a later block also runs when the variable was set and the condition false, and a guard over a Boolean enters only when it is set AND true, so a later block may see it false; reading either is legal.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 74 (How do guard variables work in if statements?)
  • ek9 -q 2002 (Can I use a '<-' guard's variable in the else block of the s...)

How to fix it

  1. Use the value inside the guarded block, where it is set.
  2. If the later block needs a value, assign one first and read it after (the fix in the [EXAMPLE] section below assigns 'fallback()' in the 'else', then prints it).
  3. If the later block needs to know what the guard saw, keep the value in a variable declared before the 'if', test that variable with '?', and read it in any block.

Common causes

  • Logging or printing the guard variable in the 'else' ("not found: ${found}") - it prints nothing
  • An operator that keeps an unset value unset ('found += 1', 'found++') - it reads the unset value
  • Note that ':=:', ':~:', ':^:' and a stream that ends '> found' give the variable a value, so they are not reads
  • Testing the guard variable again in an 'else if' condition ('else if found > limit')

See also

  • E08270: reading a '<-' guard's variable where it is provably unset (this error)
  • E08020: a variable that might be used before being initialised
  • E08089: an isSet check that data flow proves is never true

Examples

Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.

Fails with E08270: a '<-' guard's variable is always unset in the later 'else if' and 'else' blocks of its 'if' - they run because it was unset - so this read finds nothing; use it inside the guarded block, or assign it a new value first

#!ek9
defines module error.e08270.bad

  defines function

    fetch()
      <- rtn as Integer: Integer()

    demo()
      stdout <- Stdout()
      if found <- fetch()
        stdout.println(`found ${found}`)
      else
        stdout.println(`missing ${found}`)

Fixed: Use the guard variable where it is set; give the else its own value

#!ek9
defines module error.e08270.good

  defines function

    fetch()
      <- rtn as Integer: Integer()

    fallback()
      <- rtn as Integer: 1

    demo()
      stdout <- Stdout()
      if found <- fetch()
        stdout.println(`found ${found}`)
      else
        found := fallback()
        stdout.println(`fell back to ${found}`)

Questions and answers

These Q&A entries show E08270 and its fix: