Enums

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 = 0
  • Green = 1
  • Blue = 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 ref to borrow, pass by value to move, returned by value (moved to the caller).
  • == / != are not defined on them — match is the eliminator.
  • Payload types may be primitives, pointers, other enums, interfaces, and classes — including classes that own heap memory (String, Vec<T>, anything with deinit). References, arrays, and recursive payloads (without raw_ptr indirection) are rejected.
  • Payload-free enums are unchanged: plain i32 values with == comparison, usable in extern "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) moves owner into the enum; using owner afterwards is a use-after-move error.
  • Assignment moves and drops. var b = a; and b = a; move a (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 ref parameters, 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 String

Generic 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 annotation

Type 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,
}