Enums
Enums define a type with a fixed set of named variants.
Defining an Enum
enum Color { Red, Green, Blue }Each variant is automatically assigned an integer value starting from 0:
Red= 0Green= 1Blue= 2
Using Enums
Variables
Declare variables with an enum type and access variants using dot notation:
var c: Color = Color.Green;Comparison
Enum values can be compared with == and !=:
function is_red(c: Color) bool {
return c == Color.Red;
}
function main() i32 {
var c: Color = Color.Blue;
if (c != Color.Red) {
return 1;
}
return 0;
}Enums as Function Parameters
Enums can be passed to and returned from functions:
enum Direction { Up, Down, Left, Right }
function opposite(d: Direction) Direction {
if (d == Direction.Up) { return Direction.Down; }
if (d == Direction.Down) { return Direction.Up; }
if (d == Direction.Left) { return Direction.Right; }
return Direction.Left;
}
function main() i32 {
var dir: Direction = Direction.Up;
var opp: Direction = opposite(dir);
if (opp == Direction.Down) {
return 1;
}
return 0;
}Multiple Enums
You can define multiple enums in the same file:
enum Status { Pending, Running, Completed }
enum Priority { Low, Medium, High }
function main() i32 {
var s: Status = Status.Running;
var p: Priority = Priority.High;
return 0;
}Enums in Classes
Enums can be used as field types in classes:
enum TaskStatus { Pending, InProgress, Done }
class Task {
var status: TaskStatus;
function init() {
this.status = TaskStatus.Pending;
}
function start() void {
this.status = TaskStatus.InProgress;
}
function complete() void {
this.status = TaskStatus.Done;
}
function is_done() bool {
return this.status == TaskStatus.Done;
}
}Pattern Matching with Enums
Combine enums with match expressions for clean branching:
enum Color { Red, Green, Blue }
function to_rgb(c: Color) i32 {
return match c {
Color.Red => 0xFF0000,
Color.Green => 0x00FF00,
Color.Blue => 0x0000FF,
_ => 0
};
}See Match Expressions for more details.
Payload-Carrying Variants
Variants can carry data, turning an enum into a tagged union:
enum Shape {
Circle(f64), // radius
Rect(f64, f64), // width, height
Empty
}
var c = Shape.Circle(2.5);
var r = Shape.Rect(3.0, 4.0);The only way to reach a payload is a match with a destructuring pattern,
which binds each payload position to a fresh immutable local (use _ to skip
a position):
function area(s: ref Shape) f64 {
return match s {
Shape.Circle(r) => 3.14 * r * r,
Shape.Rect(w, h) => w * h,
Shape.Empty => 0.0
};
}Matches on enums are checked for exhaustiveness: every variant must be
covered, or a _ arm must be present. The error names the missing variants.
Rules for payload enums:
- They are value types with the same ownership rules as classes: pass by
refto borrow, pass by value to move, returned by value (moved to the caller). ==/!=are not defined on them —matchis the eliminator.- Payload types may be primitives, pointers, other enums, interfaces, and
classes — including classes that own heap memory (
String,Vec<T>, anything withdeinit). References, arrays, and recursive payloads (withoutraw_ptrindirection) are rejected. - Payload-free enums are unchanged: plain
i32values with==comparison, usable inextern "C"signatures. Payload enums cannot cross the C boundary yet.
Ownership and Drops
Sun never implicitly copies a compound value, and payload enums follow that rule throughout:
- Construction moves.
Holder.Hold(owner)movesownerinto the enum; usingownerafterwards is a use-after-move error. - Assignment moves and drops.
var b = a;andb = a;movea(it cannot be used again). Overwriting a variable or field that already holds a payload drops the old payload first. - Drops are automatic. When an enum whose payload owns resources goes out
of scope (block end, loop iteration,
return,break/continue, or an exception unwinding through the frame), its live payload is dropped exactly once — the compiler synthesizes a per-enum drop routine that switches on the tag. - Match bindings borrow. A binding for a compound payload refers to the
payload in place for the duration of the arm; it can be read, called, and
passed to
refparameters, but not moved out (assigned to a variable, passed by value, or returned), and the matched variable itself cannot be reassigned or moved inside the arms. Scalar payload bindings are plain copies. Moving a payload out of a match is a planned follow-up.
var maybe = Option.Some(String(alloc, "hello"));
var len = match maybe {
Option.Some(s) => s.length(), // borrows the String in place
Option.None => 0
};
maybe = Option.None; // drops the StringGeneric Enums
Enums can take type parameters, making reusable shapes like options and results expressible:
enum Option<T> { Some(T), None }
enum Result<T, E> { Ok(T), Err(E) }
function find(x: i32) Option<i32> {
if (x > 0) { return Option.Some(x * 2); } // T inferred from the argument
return Option.None; // T from the return type
}
var a = Option.Some(21); // Option<i32>, inferred
var b: Option<f64> = Option.None; // type arguments from the annotationType arguments are inferred from payload arguments where possible; a bare
unit variant like Option.None takes them from the expected type (a variable
annotation, the function return type, or an assigned field), and it is an
error when no context determines them. Each specialization is a distinct
type — Option<i32> and Option<f64> coexist independently — and matches
use the generic name in patterns:
match a {
Option.Some(v) => v,
Option.None => 0
}Not yet supported: explicit type arguments in expression position
(Option<i32>.Some(5) — use inference or an annotation), nested patterns,
arrays or globals of payload enums, and moving a payload out of a match
binding. These are planned follow-ups.
Trailing Commas
Trailing commas are allowed in enum definitions:
enum Days {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
}