Does ':=?' initialise a variable declared with no value, even when the value it assigns is unset?

← Data Flow Safety · Ref: Q2003

Yes - where the ':=?' always runs. A variable declared with no value ('x as Integer?') counts as unset, so 'x :=? f()' assigns whatever f() returned. That is an object - present, maybe unset, never absent - so x is initialised and every later use is legal: arithmetic on an unset Integer gives an unset result, not a crash.

It counts only where it always runs: a statement, the FIRST 'if' pre-flow, a 'while', 'for', 'switch' or 'try' pre-flow, a 'do' body, a 'finally'. An 'else if' pre-flow, an if/case/loop body, a try body and a catch may not run, so a variable filled only there is E08020 at its later use. 'if third :=? fetch(true)' in the head initialises third; the same ':=?' inside the if body does not.

On a variable the compiler can prove is already set, ':=?' can never apply (E08095).

See Q79 for ':=?' and Q29 for unset variables.

Example

defines module qa.dataflow.assignifunsetinitialises

  defines function

    fetch()
      -> wanted as Boolean
      <- rtn as Integer: Integer()
      if wanted
        rtn: 42

  defines program

    AssignIfUnsetInitialises()
      stdout <- Stdout()

      first as Integer?
      first :=? fetch(true)
      stdout.println(`first set=${first?} value=${first}`)

      second as Integer?
      second :=? fetch(false)
      stdout.println(`second set=${second?}`)

      total <- second + 1
      stdout.println(`second + 1 set=${total?}`)

      third as Integer?
      if third :=? fetch(true)
        stdout.println(`third filled by the if head: ${third}`)
      stdout.println(`third after the if set=${third?}`)

Common mistakes

E08020 — Inside the if body ':=?' may not run, so 'third' might still have no value when it is read afterwards. Put ':=?' where it always runs - the if head or a statement. See ek9 -h E08020 for details.

Incorrect:

      if fetch(true)?
        third :=? fetch(true)

Correct:

      if third :=? fetch(true)
        stdout.println(`third filled by the if head: ${third}`)
Other ways to ask this
  • Can I use a variable after 'x as Integer?' and 'x :=? f()'?
  • What happens when ':=?' assigns an unset value?
  • Why is my ':=?' inside an if not enough to initialise the variable?
  • Is a variable filled by ':=?' ever absent?

Coming from another language?

Kotlin: 'var x: Int? = null; x = x ?: f()' leaves x null when f() returns null. C#: 'x ??= F()' the same. EK9 has no null: ':=?' always stores an object, which may be unset, so the variable is initialised either way.

Keywords: E08020, uninitialised, assign-if-unset, initialise, absent, unset, :=?, definite assignment