E08020: might be used before being initialised

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

What went wrong

You declared a variable but are using it BEFORE assigning it a value.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 4 (How do I read input from the user?)

Mutating operators require initialized lhs

ALL mutating operators require the left-hand side to already have a value:

  • :=: (copy) and :~: (merge) - copy/merge INTO existing value
  • +=, -=, *=, /= etc. - modify existing value
  • ++, -- - increment/decrement existing value

These operators CANNOT work on uninitialized variables because there's nothing to copy into, merge with, or modify.

Stream and loop operands are reads too

A stream pipeline reads every variable it names, so each must hold a value first:

  • the sink: 'results' in 'cat items > results'
  • a tee target: 'side' in 'cat items | tee in side > out'
  • a 'with' operand: 'transform' in '| map with transform'
  • a 'by' operand: 'ordering' in '| sort by ordering'
  • a head/skip/tail count: 'count' in '| head with count'
  • a for-range step: 'step' in 'for i in 1 ... 10 by step'

Declare the variable with its value ('results <- List() of String', 'step <- 2'), or assign it before the stream or loop.

A path that ends in a throw

A path that ends in an unconditional throw never continues, so it does not count against a later read. With 'label as String?', an 'if' arm that assigns 'label: "large"' and an 'else' arm that is just 'throw Exception("Not positive")' leave 'label' set wherever the code after the if/else runs - every arm of a nested if/else or switch that throws counts. A throw inside an 'if' with no 'else' covers nothing (the other path still falls through), and a catch or finally runs AFTER the throw, so reading the variable there is still E08020 unless it was set before the try.

How to fix it

  1. Initialize at declaration: value <- initialValue
  2. Or ensure initialization happens before use
  3. For copy semantics, use: local <- Type(source) instead of :=:

Common causes

  • Variable declared without initialization
  • Using :=: or :~: on uninitialized return parameter
  • Conditional initialization not covering all paths
  • Trying to use mutating operator before first assignment

See also

  • E08020: declared but no value (this error)
  • E08010: not declared at all
  • E08050: return value not initialized on all paths

Examples

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

Fails with E08020: might be used before being initialised

#!ek9
defines module error.e08020.bad

  defines function

    describe()
      -> ready as Boolean
      <- rtn as String: "unknown"
      label as String?
      if ready
        label: "ready"
      rtn: label

    countOne()
      <- rtn as Integer: 0
      counter as Integer?
      counter++
      rtn: counter

Fixed: Give the variable a value before the paths divide

#!ek9
defines module error.e08020.good

  defines function

    describe()
      -> ready as Boolean
      <- rtn as String: "unknown"
      label <- "not ready"
      if ready
        label: "ready"
      rtn: label

    countOne()
      <- rtn as Integer: 0
      counter <- 0
      counter++
      rtn: counter

Fixed: Or assign it on every path

#!ek9
defines module error.e08020.good.every.path

  defines function

    describe()
      -> ready as Boolean
      <- rtn as String: "unknown"
      label as String?
      if ready
        label: "ready"
      else
        label: "not ready"
      rtn: label

Questions and answers

These Q&A entries show E08020 and its fix: