Declaring an Enum
enum declares a type whose values are a fixed set of named variants:
enum Status {
ready,
failed,
}
Now Status is a type with exactly two values: Status.ready and Status.failed. Nothing else can be a Status.
The grammar is intentionally tiny:
enum Name {opens the declaration.- Each line lists one variant name, comma-separated.
}closes it.
No payloads, no discriminator values, no derived methods — that's what keeps enum "the small sum type" in Zero.
Using an Enum
You name a variant by qualifying it with the enum type:
let state: Status = Status.ready
The annotation : Status is optional once the right-hand side pins the type; in most cases you can write:
let state = Status.ready
and the compiler will infer the type to be Status.
Comparing Enum Values
Two enum values are equal when they're the same variant:
if state == Status.ready {
check world.out.write("ready\n")
} else {
check world.out.write("not ready\n")
}
That's the simplest way to branch on an enum. For exhaustive analysis — handling every variant explicitly — reach for match:
match state {
.ready => { check world.out.write("ready\n") }
.failed => { check world.out.write("failed\n") }
}
The advantages of match over if/else if show up when you add a third variant later. The compiler will tell you every match that's missing the new case; an if/else chain will silently fall through to its default branch.
Choice and match covers match in more detail. It works for both enum and choice.
A Worked Example
The official Zero sample puts enum and choice side by side in the same file:
Status doesn't do anything in this snippet — it's there to show the contrast. A choice variant binds a payload (value, message) when matched; an enum variant binds nothing because there's nothing to bind.
Enum vs. Choice: A Quick Decision Tree
A short rule:
- The variants are just labels →
enum. - The variants have to carry data →
choice.
If you're modeling lifecycle states and you eventually need to attach an error message to the "failed" state, switch the type from enum to choice. The variants get a payload type each, and downstream match arms gain a binding for that payload. It's a refactor the compiler walks you through.
Concretely:
// Before — enum, no payloads
enum Status {
ready,
failed,
}
// After — choice with payloads on each variant
choice Status {
ready: Void,
failed: String,
}
The variants whose payload is Void are just labels in choice form. You can use enum and choice for the same logical states; pick enum when you genuinely don't need data attached.
Use Cases
Some everyday examples where enum is the right answer:
- Lifecycle without metadata.
Loading,Ready,Empty— pure states, no payloads. - Modes.
Read,Write,Appendfor a file open mode. - Direction.
North,South,East,West. - Log level.
Trace,Debug,Info,Warn,Error. (You might later add a message, at which point you'd switch tochoice.) - Day of the week. A canonical example.
Whenever you'd otherwise reach for a magic integer constant (0 = pending, 1 = active, 2 = done), an enum is almost always clearer.
Style Notes
- Lowercase variant names match Zero's style for identifiers across the rest of the language.
- A trailing comma after the last variant is fine (and recommended for diff-friendliness — adding a new variant doesn't churn the previous line).
- Keep enum lists small. If you have a dozen variants and many of them want payloads, you might be looking at a
choice— or a redesign — rather than a biggerenum.
Next: Choice and Match
The natural next step is the richer cousin: choice and match — Zero's tagged-union type and the pattern-matching construct that goes with it.
Frequently Asked Questions
What is an enum in Zero?
An enum declares a type whose values are one of a fixed set of named variants — labels without any extra payload. Example: enum Status { ready, failed }. A value of type Status is exactly one of Status.ready or Status.failed, and the compiler enforces that.
How is enum different from choice?
An enum's variants are plain labels — they don't carry data. A choice is a tagged union — each variant has an associated payload type, like choice Result { ok: i32, err: String }. Use enum when you only need to distinguish cases by name; use choice when each case carries extra information.
How do you check which enum variant a value has?
Compare the value to the variant: if status == Status.ready { ... }. For exhaustive branching across all variants, use match — the compiler will warn if you miss a variant, which is the main reason to prefer match over if/else if chains when the value is a sum type.
Can enum variants have associated values in Zero?
No — that's what choice is for. enum is deliberately the minimal sum type: each variant is just a label. If you need to attach an i32 or a String to one of the variants, you've outgrown enum and want a choice.
When should you use an enum in Zero?
Use enum when a value has to be exactly one of a small, named set of states and those states don't carry extra data. Examples: day of the week, traffic-light color, lifecycle state with no metadata, a logging level. If you find yourself wanting to attach data to one of the variants, switch to choice.