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. If either operand is unset, the result is unset. This propagates the 'unknown' state correctly rather than silently treating it as false.

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")

If the string is not 'true' or 'false', the Boolean becomes unset rather than throwing an exception. This follows the tri-state pattern: invalid input produces an unset value you can check with ?.

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")
      stdout.println(`from text: ${fromText?}, invalid: ${invalid?}`)

      // Guarded assignment
      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.

Keywords: bool, unset, migrate, not, tri-state, xor, tristate, true, logical, and, false, intro, boolean, or, first, beginner, complement, start