Tagged Enums, Pattern Matching, Generics & Traits

Ube combines tagged sum types with compile-time monomorphized generics and dynamic trait dispatch, providing expressive modeling without runtime overhead.

1. Tagged Enums with Variant Payloads

Enums in Ube are tagged unions. Each variant can carry zero, one, or multiple payload types:

enum GameAction {
    Move(f32, f32),      // Carries coordinates (x, y)
    Attack(i32),         // Carries damage amount
    UseItem(string),     // Carries item name
    Idle                 // Unit variant without payload
}

fn main() {
    let act1 = GameAction.Move(15.0, 30.0)
    let act2 = GameAction.Idle
}

2. Exhaustive Pattern Matching with match

The match expression destructures enum variants. Matching is exhaustive: the compiler verifies that every possible variant is covered:

fn dispatch_action(action: GameAction) {
    match action {
        Move(x, y) => {
            println(f"Entity moving towards position ({x}, {y})")
        },
        Attack(damage) => {
            println(f"Entity attacking for {damage} damage points!")
        },
        UseItem(name) => {
            println(f"Entity consumed potion/item: {name}")
        },
        Idle => {
            println("Entity remains idle.")
        }
    }
}

fn main() {
    let act = GameAction.Attack(75)
    dispatch_action(act)
}

3. Monomorphized Generics

Generic structs and functions are written with [T]. Generics in Ube are fully monomorphized at compile time, meaning specialized native code is generated for each concrete type with zero runtime boxing overhead:

struct Container[T] {
    item: T
}

fn wrap_value[T](value: T) -> Container[T] {
    return Container[T] {
        item: value
    }
}

fn main() {
    let int_box = wrap_value[i32](42)
    println(f"Boxed integer: {int_box.item}")

    let float_box = wrap_value[f32](3.14)
    println(f"Boxed float: {float_box.item}")
}

4. Dynamic Traits & Interface Boxing

When heterogeneous objects must be handled uniformly at runtime, Ube provides trait definitions. Any struct implementing the declared methods automatically satisfies the trait:

trait Renderable {
    fn draw() -> string
}

struct Circle {
    radius: f32
}

fn (c Circle) draw() -> string {
    return f"Drawing circle of radius {c.radius}"
}

struct Rectangle {
    width: f32,
    height: f32
}

fn (r Rectangle) draw() -> string {
    return f"Drawing rectangle {r.width}x{r.height}"
}

// Accepts any Renderable dynamically
fn display_shape(shape: Renderable) {
    println(shape.draw())
}

fn main() {
    display_shape(Circle { radius: 5.0 })
    display_shape(Rectangle { width: 10.0, height: 4.0 })
}