What are the names of EK9's '?' operators - '?', '<-', ':=', ':=?', '?:' and '<?'?

← Operators and Expressions · Ref: Q2004

One name per symbol, used everywhere in EK9:
- 'x?' is the SET-CHECK: true when x holds a meaningful value
- '<-' is a DECLARATION; in an if/switch/for/while/do/try head it is a DECLARATION GUARD (enter only if set)
- ':=' (also '=' and ':') is an ASSIGNMENT; in a head it is blind, so add 'then x?'
- ':=?' is ASSIGN-IF-UNSET: it fills the target only if it is unset ('a :=? b' is 'a := a ?: b')
- '?:' is COALESCE (Elvis): the left if set, otherwise the right, evaluated only then
- '<?' '<=?' '>?' '>=?' are COMPARISON COALESCING: they return one of their operands - the set one, or the lesser/greater

A GUARD is the idea 'enter only if set' - like Swift's 'if let'. There is no '?=' operator and no assignment yields a value: to know whether a new value is set, assign and then check, 'x := f()' then 'ok <- x?'. A coalescing operator mixed with another binary operator must be parenthesised (E08269).

See Q79 for ':=?', Q1091 for '?:', Q939 for the comparison coalescing operators and Q1980 for the head forms.

Example

defines module qa.operators.questionmarknames

  defines function

    textOf()
      -> text as String
      <- rtn as String: text

    countOf()
      -> count as Integer
      <- rtn as Integer: count

  defines program

    QuestionMarkNames()
      stdout <- Stdout()
      maybe <- textOf(String())

      //set-check: x?
      stdout.println(`set-check: maybe? is ${maybe?}`)

      //declaration guard: <- in a head
      if guarded <- textOf("guarded")
        stdout.println(`declaration guard entered with ${guarded}`)

      //assign-if-unset: :=? fills only an unset target
      maybe :=? "filled"
      stdout.println(`assign-if-unset: maybe is ${maybe}`)

      //assignment: := is blind, so check the new value with then x?
      entered <- false
      if maybe := textOf(String()) then maybe?
        entered: true
      stdout.println(`assignment re-pointed maybe: set is ${maybe?}, entered is ${entered}`)

      //coalesce (Elvis): the left if set, otherwise the right
      chosen <- maybe ?: "fallback"
      stdout.println(`coalesce: ${chosen}`)

      //comparison coalescing: returns an operand - the set one, or the lesser
      lower <- countOf(Integer()) <? countOf(7)
      stdout.println(`comparison coalescing: ${lower}`)

Common mistakes

E07340 — An assignment in a head is blind - it checks nothing - so the if has no condition. Add 'then maybe?' to enter only when the new value is set. See ek9 -h E07340 for details.

Incorrect:

      if maybe := textOf(String())

Correct:

      if maybe := textOf(String()) then maybe?

E08269 — '?:' binds tighter than '+', so this would be (maybe ?: "fallback") + "!". Parenthesise whichever is meant. See ek9 -h E08269 for details.

Incorrect:

      chosen <- maybe ?: "fallback" + "!"

Correct:

      chosen <- maybe ?: "fallback"
Other ways to ask this
  • What is the difference between ':=?' and ':='?
  • Is there a '?=' operator in EK9?
  • What do I call ':=?' and '?:'?
  • Which of EK9's operators check whether a value is set?

Coming from another language?

C#/JavaScript: '??=' is EK9's ':=?' and '??' is close to EK9's '?:' (EK9 also falls back for an UNSET value). Kotlin: '?:' is the same name and shape. Swift: 'if let' is EK9's declaration guard. Groovy's '?=' does not exist in EK9.

Keywords: :=?, <?, Elvis, assign-if-unset, names, <-, ?:, ?, :=, comparison coalescing, coalesce, declaration guard, set-check