Skip to content

Enums

Enums in Nic are algebraic data types (ADTs). Each variant can hold different data, making them powerful for modeling state and results.

Simple Enums

nic
enum Color {
    Red,
    Green,
    Blue
}

fn main() -> unit {
    let c: Color = Red;
    
    match c {
        Red -> println("red"),
        Green -> println("green"),
        Blue -> println("blue")
    };
    
    return;
}

Enums with Data

Variants can carry values:

nic
enum Shape {
    Circle(f64),              // radius
    Rectangle(f64, f64),      // width, height
    Point                     // no data
}

fn area(s: Shape) -> f64 {
    return match s {
        Circle(r) -> 3.14159 * r * r,
        Rectangle(w, h) -> w * h,
        Point -> 0.0
    };
}

fn main() -> unit {
    let circle: Shape = Circle(5.0);
    let rect: Shape = Rectangle(10.0, 20.0);
    
    let a1: f64 = area(circle);     // ~78.5
    let a2: f64 = area(rect);       // 200.0
    
    return;
}

Option Type

The prelude provides Option[T] for optional values:

nic
enum Option[T] {
    Some(T),
    None
}

fn find(arr: []i32, target: i32) -> Option[i32] {
    // ... search logic
    return None;
}

fn main() -> unit {
    let maybe: Option[i32] = Some(42);
    
    match maybe {
        Some(x) -> println("found"),
        None -> println("not found")
    };
    
    return;
}

Use helper functions from the prelude:

nic
fn main() -> unit {
    let opt: Option[i32] = Some(42);
    
    let value: i32 = unwrap_or(opt, 0);  // 42
    let has_value: bool = is_some(opt);   // true
    let is_empty: bool = is_none(opt);    // false
    
    return;
}

Result Type

For error handling, use Result[T, E]:

nic
enum Result[T, E] {
    Ok(T),
    Err(E)
}

fn divide(a: f64, b: f64) -> Result[f64, string] {
    if b == 0.0 {
        return Err("division by zero");
    }
    return Ok(a / b);
}

fn main() -> unit {
    let result: Result[f64, string] = divide(10.0, 2.0);
    
    match result {
        Ok(value) -> println("success"),
        Err(msg) -> println("error")
    };
    
    return;
}

Generic Enums

nic
enum List[T] {
    Nil,
    Cons(T, *List[T])
}

fn length[T](list: *List[T]) -> i32 {
    return match *list {
        Nil -> 0,
        Cons(_, tail) -> 1 + length(tail)
    };
}

Record Variants

Variants can have named fields:

nic
enum Event {
    Click{x: i32, y: i32},
    KeyPress{key: char},
    Quit
}

fn handle(e: Event) -> unit {
    match e {
        Click{x: x, y: y} -> println("click"),
        KeyPress{key: k} -> println("key"),
        Quit -> println("quit")
    };
    return;
}

Recursive Enums

Enums can reference themselves through pointers:

nic
enum Tree[T] {
    Leaf(T),
    Node(*Tree[T], *Tree[T])
}

fn count_leaves[T](tree: *Tree[T]) -> i32 {
    return match *tree {
        Leaf(_) -> 1,
        Node(left, right) -> count_leaves(left) + count_leaves(right)
    };
}

Visibility

nic
pub enum PublicEnum {
    VariantA,
    VariantB(i32)
}

Summary

FeatureSyntax
Simpleenum Name { A, B, C }
With dataenum Name { A(T), B(T, U) }
Record variantenum Name { A{field: T} }
Genericenum Name[T] { A(T), B }
Matchmatch value { Variant(x) -> expr }

Next

Dive deeper into Pattern Matching.

Released under the MIT License.