What is the default value of an unset variable?
← Getting Started · Ref: Q29
EK9 has no null. Every object exists in one of three states: absent, present but unset, or present and set. The ? operator checks whether an object is set.
THE THREE STATES
Absent: object does not exist (a Dict lookup miss). Note an empty Optional is NOT absent: it is a real object that is present but unset, so use '?:' (unset-or-absent) to default it. Present but unset: object exists, no meaningful value. String() is unset. ? returns false. Present and set: object has valid value. String("hello") is set. ? returns true.
CHECKING STATE WITH ?
name <- String() stdout.println(`Name is set: ${name?}`) // false: present, but unset
Assign-if-unset :=? only assigns if unset:
name :=? "default" assigns because unset name :=? "other" no-op because already set
GUARDS IN CONTROL FLOW
if record <- database.find(key) stdout.println(`Found: ${record}`)
Works identically in if, switch, for, while, and try.
TYPE-SPECIFIC BEHAVIOUR
- Primitives (String, Integer, Float, Boolean, Character): unset when created with no argument.
- Collections (List, Dict): always set when created, even if empty.
- Containers (Optional, DictEntry): depends on contained value.
INVALID CONSTRUCTION CREATES UNSET
parsed <- Integer("not a number") if parsed? false — invalid input produces unset, no exception
BOOLEAN TRI-STATE
Boolean() is unset (not yet known), distinct from Boolean(false).
JSON MAPPING
Absent: field omitted. Unset: field as null. Set: field has value.
Critical for REST PATCH distinguishing 'not provided' from 'clear value' from 'update'.
WHY NOT NULL?
Null is 'the billion-dollar mistake'. EK9's tri-state replaces it: objects always exist, ? checks for meaningful value, guards prevent processing unset values, compiler enforces handling.
See Q22 for :=? assign-if-unset. See Q26 for unified object model. See Q30 for Boolean tri-state. See Q47 for Optional. See Q48 for Result. See Q104 for uninitialised properties. See Q141 for constants. See Q188 for JSON. See Q222 for enum unset state. See Q243 for coalescing operators. See Q251 for unset variable errors. See Q256 for Void type. See Q261 for idiomatic patterns. See Q269 for input validation. See Q277 for AI null checks vs guards. See Q286 for assign-if-unset accumulation. See Q2251 and Q2252 for what a String, a counter or a total starts from, and Q2253 for why '+=' on an unset value is reported (E08096).
Example
#!ek9 defines module qa.unset.variables defines function savedNickname() as pure <- rtn as String: String() defines program UnsetVariablesDemo() stdout <- Stdout() // Present but unset name <- String() stdout.println(`Name is set: ${name?}`) // Present and set greeting <- "Hello" stdout.println(`Greeting is set: ${greeting?}`) // Assign-if-unset - only assigns if unset nickname <- savedNickname() nickname :=? "default" stdout.println(`Nickname after guard: ${nickname}`) nickname :=? "other" stdout.println(`Nickname after second guard: ${nickname}`) // Guard in control flow items <- List() of String items += "first" // Collections are always set when created stdout.println(`Items is set: ${items?}`) emptyList <- List() of Integer stdout.println(`Empty list is set: ${emptyList?}`) // Unset integer count <- Integer() stdout.println(`Unset count: ${count?}`) //Known to be unset here, so ':=' - a ':=?' would always apply (E08097) count := 42 stdout.println(`Count after assignment: ${count}`)
Other ways to ask this
- What happens when a variable has no value in EK9?
- How does the tri-state object model work in EK9?
- Does EK9 have null?
- How do I check if a variable is set in EK9?
Coming from another language?
Java: null/NullPointerException. Rust: Option<T>. Kotlin/Swift: nullable types. Python: None. JS: null AND undefined. EK9: tri-state (absent/unset/set), no null, ? operator, :=? assign-if-unset, guards in control flow.
Keywords: absent, beginner, billion, default, first, intro, migrate, mistake, null, start, swift, tri-state, tristate, undefined, unset, value