9Enums
Cryo enums are algebraic data types. Variants may be unit or carry a payload. The compiler enforces exhaustive matching.
9.1 Unit Enums
type enum Color {
Red;
Green;
Blue;
}
const c: Color = Color::Red;
Variants are accessed through the enum name with ::, so Color::Red and TrafficLight::Red are unambiguous.
Variants may have explicit integer values for FFI or protocol encoding:
type enum ErrorCode {
Ok = 0;
NotFound = 404;
Internal = 500;
}
9.2 Variants with Payloads
A variant can carry one or more values:
type enum Shape {
Circle(f64);
Rectangle(f64, f64);
Point;
}
const s: Shape = Shape::Circle(5.0);
A Shape value is always exactly one variant; the compiler tracks which one and enforces exhaustive matching.
9.3 Generic Enums
Enums can be parameterised over types. The standard library's Option and Result are the canonical examples:
type enum Option<T> {
Some(T);
None;
}
type enum Result<T, E> {
Ok(T);
Err(E);
}
const v: Option<int> = Option::Some(42);
const r: Result<string, int> = Result::Ok("success");
Each instantiation is an independent type at the machine level; Option<int> and Option<string> share no runtime representation.
A variant constructs one instantiation, and something must say which: type arguments written on the path (Option::<i32>::None, Result::Ok::<i32, i32>(4)), the expected type (an annotation, a parameter, a return type), or the variant's own arguments (Option::Some(42) is an Option<i32>). A variant nothing instantiates - const n = Option::None;, or Result::Ok(1) with E unbound - is refused (E0307). Type arguments written on the path also type the payload: Result::<i32, i32>::Ok("x") is refused (E0214), and in Option::<u8>::Some(200) the literal is a u8.
9.4 Methods on Enums
Enums cannot declare methods inline. Methods are added via an implement block, which is also how the standard library gives Option and Result their rich API:
implement enum Option<T> {
is_some(&this) -> boolean {
match (this) {
Option::Some(_) => { return true; }
Option::None => { return false; }
}
}
unwrap(&this) -> T {
match (this) {
Option::Some(value) => { return value; }
Option::None => {
panic("unwrap on None", intrinsics::location());
}
}
}
}
See section 12 for the full implement-block grammar.
type struct Name { ... }
type enum Name { ... }
type trait Name { ... }
type union Name { ... }Begins a type declaration; the keyword that follows says which kind. On its own, type Name = Existing; declares an alias.
type enum Name {
Unit,
Payload(T),
Named { x: i32 },
}An algebraic data type. Variants may be bare or carry a tuple or struct payload, and a match on an enum must cover every variant. Name::Variant names a variant; methods are added with implement enum Name { ... }.
type enum ColorColor::RedColor::GreenColor::Blueconst NAME: Type = value;At module level, a true compile-time constant, conventionally SCREAMING_SNAKE_CASE. (mut at module level declares mutable global state instead.)
const c: Colortype enum ColorColor::Redtype enum ErrorCodeErrorCode::OkErrorCode::NotFoundErrorCode::Internaltype enum ShapeShape::Circle(f64)Shape::Rectangle(f64, f64)Shape::Pointconst s: Shapetype enum ShapeShape::Circle(f64)type enum Option<T>type parameter TOption::Some(T)type parameter TOption::Nonetype enum Result<T, E>type parameter EResult::Ok(T)type parameter TResult::Err(E)type parameter Econst v: Option<int>type enum Option<T>Option::Some(T)const r: Result<string, int>type enum Result<T, E>primitive stringNUL-terminated raw string (u8*), matching the C ABI. Length-typed text is Str / String.
Result::Ok(T)implement struct Name { ... }
implement trait Trait for Type { ... }
implement u64 { ... }Adds methods to a type outside its declaration. implement struct T (or enum, or a bare primitive) opens an inherent block; implement trait Tr for T supplies a trait's methods for one type. Resolution is at compile time - no dynamic dispatch.
implement enum Name { ... }Names the enum an inherent block extends - the only way to give an enum methods.
language referencetype enum Option<T>Option::is_some(&this) -> boolean&this
mut &this
thisThe receiver of a method. Its first parameter declares how the method takes it: &this borrows read-only, mut &this borrows exclusively, and this / mut this move the value in and consume it. In the body, this.field reaches the members.
match (subject) {
Pattern(x) => { ... }
_ => { ... }
}The primary discriminator: branches on enum variants, integers, ranges, and destructuring patterns, and the compiler rejects a match that misses a case. There is no fallthrough. As an expression it evaluates to the chosen arm's value, so every arm must produce the same type.
Option::Some(T)_pattern => { body }Separates a match arm's pattern from its body. Arms do not fall through.
return value;Leaves the current function with the given value. A function whose return type is not void must return one; a bare return; is for void. In an async function it completes the future with the value.
trueThe boolean literal. Booleans are a distinct 1-byte type, not interchangeable with integers; if and while conditions must be boolean.
Option::NonefalseThe boolean literal. Booleans are a distinct 1-byte type, not interchangeable with integers; if and while conditions must be boolean.
Option::unwrap(&this) -> Ttype parameter Tvalueintrinsic function panic(message: string, loc: Location) -> nevertype enum ColorColor::Redtype enum Shapetype enum Result<T, E>Result::Ok(T)const n