Does 'if allowed <- permitted()' run its body when permitted() returns false?
← Control Flow · Ref: Q2001
No. A guard normally enters when its value is SET, but over a Boolean an 'if' (or 'else if') guard enters only when the value is SET AND TRUE. 'if allowed <- permitted(user)' skips the body for false just as it does for an unset result, so no trailing 'then allowed' is needed. The same holds for ':=?' in an if head: 'if decision :=? permitted(false)' fills decision with false and skips the body.
It is deliberately narrow:
- only 'if' and 'else if'; a 'switch' keeps enter-if-set, so its 'case false' stays reachable, and so do 'while', 'do', 'for' and 'try'
- only '<-' and ':=?'; a ':=' head is blind (E07340 without a condition)
- only a variable DECLARED Boolean; a type that merely promotes to Boolean keeps enter-if-set
An unset Boolean skips the body as any unset value does.
See Q74 for the guard in an if and Q1980 for the head forms side by side.
Example
#!ek9 defines module qa.controlflow.booleantruthguard defines function permitted() -> allowed as Boolean <- rtn as Boolean: allowed unknown() <- rtn as Boolean: Boolean() defines program BooleanTruthGuard() stdout <- Stdout() if granted <- permitted(true) stdout.println(`if over true: entered, granted=${granted}`) if refused <- permitted(false) stdout.println(`if over false: entered, refused=${refused}`) else stdout.println("if over false: skipped") if missing <- unknown() stdout.println(`if over unset: entered, missing=${missing}`) else stdout.println("if over unset: skipped") decision <- Boolean() if decision :=? permitted(false) stdout.println(`fill with false: entered, decision=${decision}`) else stdout.println(`fill with false: skipped, decision set=${decision?}`) switch answer <- permitted(false) case true stdout.println("switch over false: case true") case false stdout.println(`switch over false: case false, answer=${answer}`) default stdout.println("switch over false: default")
Common mistakes
E07340 — ':=' in a head is a blind assignment and checks nothing, so the if has no condition. Use ':=?' (which fills an unset target and, over a Boolean in an if, enters only when true) or add 'then decision'. See ek9 -h E07340 for details.
Incorrect:
if decision := permitted(false)
Correct:
if decision :=? permitted(false)
Other ways to ask this
- How does a guard behave when the value is a Boolean?
- Why is my if guard skipped when the Boolean is false?
- Does a switch guard over a Boolean still reach case false?
- Is 'then allowed' needed after 'if allowed <- check()'?
Coming from another language?
Swift: 'if let allowed = permitted()' enters for false (it only unwraps). Kotlin: 'permitted()?.let { }' enters for false. Java: 'if (Boolean.TRUE.equals(permitted()))' is the null-safe truth test. EK9: the guard over a Boolean is that null-safe truth test, in an if.
Keywords: Boolean, assign-if-unset, case false, declaration guard, else if, guard, if, switch, truth