How do I work with Boolean values?
← Getting Started · Ref: Q30
In most languages, a Boolean is either true or false. In EK9, a Boolean has three states: true, false, and unset. An unset Boolean is neither true nor false. It means 'not yet determined' or 'we do not know yet'. This is a fundamental difference.
Consider a medical test result. 'Negative' (false) and 'we have not run the test yet' (unset) are completely different states. In Java, Python, or Go, an uninitialised boolean defaults to false, which silently conflates 'no' with 'unknown'. EK9 makes the distinction explicit.
CREATING BOOLEANS
ready <- true failed <- false unknown <- Boolean()
The first two are set. The third exists but is unset. Use ? to check:
if ready? stdout.println("ready has a value") if unknown? stdout.println("this will not print")
LOGICAL OPERATORS
EK9 provides four logical operators:
- and: Logical conjunction: true and false gives false - or: Logical disjunction: true or false gives true - xor: Exclusive or: true xor true gives false, true xor false gives true - not: Logical negation: written as 'not' keyword - ~: Complement operator: ~true gives false, ~false gives true
These operators work on set Boolean values. An unset operand makes the result unset, propagating the 'unknown' state rather than silently treating it as false - unless the LEFT operand already decides the result: 'and' and 'or' short-circuit, so false and X is a set false, and true or X is a set true, whatever X is. With the unset value on the left (unset and false, unset or true), or with xor and ~, the result is unset.
COMPARISON OPERATORS
== Equality: true == true gives true <> Inequality: true <> false gives true <=> Comparison: returns Integer for ordering
OTHER OPERATORS
- $: String conversion: $ready gives "true" - $$: JSON conversion - :=: Copy assignment - :^: Replace assignment - :~: Merge assignment - +=: Accumulate (logical or) - +: Addition (logical or, pure) - |: Pipeline operator
BOOLEAN FROM STRING
You can construct a Boolean from a String:
fromText <- Boolean("true") invalid <- Boolean("maybe")
Only the text 'true' (in any case) gives true. Any other set String, 'maybe' included, gives a SET false - no exception is thrown, and the result is not unset. Only an unset String gives an unset Boolean. So Boolean("maybe")? is true and its value is false; validate the text first if 'maybe' must not mean false.
WHY TRI-STATE MATTERS
In Java: boolean defaults to false. Did the user decline, or did we forget to ask?
In Python: bool defaults to False. Is the flag off, or was it never configured?
In Go: bool defaults to false. Is the check complete with a negative result, or was it never performed?
In JavaScript: undefined, null, and false are all falsy but mean different things.
EK9 eliminates this ambiguity. Boolean() is unset. Boolean(true) is true. Boolean(false) is false. Three distinct states, three distinct meanings.
For locale-specific Boolean display, see Q44 (How does the Locale type work in EK9?).
See also Q29 (What is the default value of an unset variable?) for the full tri-state model. See Q47 for how the ? operator is used with Optional types. See Q244 for boolean and bitwise operators (and, or, xor, ~).
Example
defines module qa.boolean.values defines program BooleanDemo() stdout <- Stdout() // Three states ready <- true failed <- false unknown <- Boolean() stdout.println(`ready: ${ready}, is set: ${ready?}`) stdout.println(`failed: ${failed}, is set: ${failed?}`) stdout.println(`unknown is set: ${unknown?}`) // Logical operators both <- ready and failed either <- ready or failed exclusive <- ready xor failed flipped <- ~ready stdout.println(`and: ${both}, or: ${either}`) stdout.println(`xor: ${exclusive}, complement: ${flipped}`) // Boolean from String fromText <- Boolean("true") invalid <- Boolean("maybe") //Any text other than 'true' gives a SET false, not an unset Boolean stdout.println(`from text: ${fromText?}, invalid set: ${invalid?}, value: ${invalid}`) // Assign-if-unset unknown :=? true stdout.println(`unknown after guard: ${unknown}`)
Common mistakes
E07620 — EK9 logical operators require Boolean operands. Using an Integer where a Boolean is expected triggers E07620 — type incompatibility. Use a comparison operator to produce a Boolean. See ek9 -h E07620 for details.
Incorrect:
both <- ready and 42
Correct:
both <- ready and failed
Other ways to ask this
- What logical operators does EK9 have?
- Can a Boolean be unset in EK9?
- How does Boolean tri-state work in EK9?
Coming from another language?
Java: boolean defaults to false, Boolean wrapper can be null (NPE risk). Python: bool defaults to False, truthy/falsy rules for other types. Go: bool defaults to false, no nullable bool. JavaScript: undefined/null/false all falsy with different semantics. Rust: bool is true/false, Option<bool> for tri-state. C#: bool defaults to false, Nullable<bool> for tri-state. EK9: Boolean has three states (true, false, unset), logical operators (and, or, xor, not, ~), unset propagates through operations unless a short-circuiting left operand already decides the result (false and X, true or X).
Keywords: true, tristate, xor, tri-state, not, migrate, unset, bool, start, complement, beginner, first, or, boolean, intro, false, and, logical