What happens when an EK9 enum is unset?
← Enumerations · Ref: Q222
EK9 enumerations follow tri-state semantics: a variable can be set to a specific member, or it can be unset. There is no null, no exception, and no undefined behaviour.
THREE WAYS TO GET UNSET
Priority() creates an unset enum. Priority("Invalid") returns unset when the string does not match any member. Incrementing past the last member or decrementing before the first member also produces unset.
UNSET PROPAGATION
Comparison with an unset enum returns an unset Boolean. String conversion of an unset enum returns an unset String. JSON conversion of an unset enum returns an unset JSON. The unset state flows through operations naturally.
FIRST AND LAST ON UNSET
The #< (first) and #> (last) operators are type-level operations. They always return the first or last declared member, even when applied to an unset variable. This makes them safe anchors for restarting navigation.
CHECKING WITH ?
Use the ? operator to check if an enum is set. Guard expressions work naturally: 'if checked <- getStatus()' only enters the block when the result is set.
See Q29 for unset variables. See Q219 for all auto-generated operators. See Q220 for navigation. See Q221 for string comparison.
Example
defines module qa.enums.unset defines type Priority Low Medium High Critical defines program EnumUnsetDemo() stdout <- Stdout() // === THREE WAYS TO GET UNSET === fromDefault <- Priority() stdout.println(`Default constructor isSet: ${fromDefault?}`) fromBadString <- Priority("Urgent") stdout.println(`Bad string isSet: ${fromBadString?}`) pastLast <- Priority.Critical pastLast++ stdout.println(`Past last isSet: ${pastLast?}`) // === UNSET PROPAGATION === unsetPriority <- Priority() setPriority <- Priority.High eqResult <- unsetPriority == setPriority stdout.println(`Unset == Set isSet: ${eqResult?}`) cmpResult <- unsetPriority <=> setPriority stdout.println(`Unset <=> Set isSet: ${cmpResult?}`) unsetStr <- $unsetPriority stdout.println(`Unset string isSet: ${unsetStr?}`) unsetHash <- #?unsetPriority stdout.println(`Unset hashcode isSet: ${unsetHash?}`) // === FIRST AND LAST STILL WORK ON UNSET === firstFromUnset <- #< unsetPriority stdout.println(`First from unset: ${firstFromUnset}`) lastFromUnset <- #> unsetPriority stdout.println(`Last from unset: ${lastFromUnset}`) // === CHECKING WITH ? === if setPriority? stdout.println(`Set priority: ${setPriority}`) if unsetPriority? stdout.println("This will not print")
Common mistakes
E50060 — EK9 enumerations do not have an 'equals()' method. Use the == operator for equality comparison. The == operator handles unset values safely by producing an unset Boolean result. See ek9 -h E50060 for details.
Incorrect:
eqResult <- unsetPriority.equals(setPriority)
Correct:
eqResult <- unsetPriority == setPriority
Other ways to ask this
- How does EK9 handle null enum values?
- What is the tri-state behaviour of EK9 enumerations?
- How does unset propagation work with EK9 enums?
Coming from another language?
Java: throws NullPointerException on null enum reference, IllegalArgumentException on bad valueOf(). Python: raises ValueError on invalid Enum construction, None requires explicit null checks. Rust: Option<EnumType> requires explicit unwrapping with match or if-let, no propagation. Go: zero value is integer 0 which may silently represent a valid enum constant. C#: nullable enum exists but no propagation semantics, requires explicit null checks. Kotlin: nullable enum with ?. operator but no systematic unset propagation. EK9: systematic tri-state with natural propagation through all operators, check with ? when ready.
Keywords: safe, enumeration, absent, unset, enum, propagation, exception, tri-state, null, check, set