How do I assign a value and get a Boolean saying whether the new value is set?

← Control Flow · Ref: Q759

In EK9 an assignment never yields a value, so the assignment and the set-check are two steps: assign with ':=', then test the target with '?'. ':=' ALWAYS evaluates the right-hand side and ALWAYS stores it - an unset result included - so afterwards the target holds exactly what was returned and 'name?' says whether it is SET. (EK9 has no '?=' operator; it was removed so that no assignment yields a value.)

ASSIGN, THEN CHECK

  name as String?
  name := getValue()
  guardResult <- name?

Here guardResult is a Boolean: true if getValue() returned a set value, false otherwise. Either way name now holds what getValue() returned, so it is initialised and safe to use.

WHEN THE RHS IS UNSET

The unset value is still stored - it OVERWRITES a set target - and the check is false:

  existing <- "already here"
  existing := getEmpty()
  result <- existing?
  // result is false, existing is now UNSET

TO KEEP AN EXISTING VALUE

If the old value must survive a missing new one, coalesce: 'existing := getEmpty() ?: existing', or fill only an unset target with ':=?' (assign-if-unset).

IN A CONTROL-FLOW HEAD

The same two steps fit in one head: 'if name := f() then name?' assigns, then runs the body only if name is now set.

See Q74 for guard variables in if. See Q77 for guard variables in while. See Q79 for the assign-if-unset :=? operator. See Q1024 for re-point-and-check in control flow.

Example

defines module qa.flow.guard.expression.boolean

  defines function

    getValue()
      <- rtn <- String()
      rtn: "hello"

    getEmpty()
      <- rtn <- String()

  defines program

    GuardExpressionBooleanDemo()
      stdout <- Stdout()

      // === ASSIGN A SET VALUE, THEN CHECK ===

      name as String?
      name := getValue()
      guardResult <- name?
      stdout.println(guardResult)
      stdout.println(name)

      // === ASSIGN AN UNSET VALUE - it overwrites existing ===

      existing <- "already here"
      existing := getEmpty()
      guardResult2 <- existing?
      stdout.println(guardResult2)
      stdout.println(existing?)

      stdout.println("Done")

Common mistakes

E50030 — 'name?' is a Boolean, not the type of the assigned value. Declaring the result as String triggers E50030 because Boolean and String are incompatible. Use type inference with '<-' to get the correct Boolean type. See ek9 -h E50030 for details.

Incorrect:

guardResult as String: name?

Correct:

guardResult <- name?
Other ways to ask this
  • Can an assignment return a Boolean in EK9?
  • Is there a ?= operator in EK9?
  • How do I assign and then check isSet in one place?

Coming from another language?

Java: 'name = getValue(); boolean assigned = name != null;'. Kotlin: 'name = getValue(); val ok = name != null'. Python: 'name = getValue(); ok = name is not None'. EK9: 'name := getValue()' then 'ok <- name?' - the same two steps, and name is never a null afterwards because an unset value is still an object.

Keywords: null-safe, operator, return, conditional, assignment, isset, check, result, source, safe, guard, standalone, expression, boolean