BRAIDGROUP
RESEARCH & DEV
14. Documentation

Generics

Current Status

Braid v1 has limited generics support. The parser tokenizes and parsesType<SubType> syntax, and the Hindley-Milner type checker supports type variables and unification, but full generic functions and data structures are not yet implemented. Polymorphism is achieved through struct composition, loose typing vianil, and code generation patterns.

Generic Type Syntax in the Parser

The parser does handle generic type annotations. When a type name is followed by<Type>, it is parsed as a generic type with sub-parameters.

let list: List<int>;
let map: Map<string, float>;
let maybe: Option<string>;

fn process(items: List<int>) {
    let first = items[0];
    print(first);
}

Template Patterns via Macros

In the absence of full generics, you can use code generation patterns. Define type-specific versions of your logic by hand or via a build-time step.

struct IntStack {
    data: int[];
    count: int;
}

impl IntStack {
    fn new() -&gt; IntStack {
        return IntStack { data: [], count: 0 };
    }

    fn push(self, val: int) {
        self.data[self.count] = val;
        self.count = self.count + 1;
    }

    fn pop(self) -> int {
        self.count = self.count - 1;
        return self.data[self.count];
    }
}

struct FloatStack {
    data: float[];
    count: int;
}

impl FloatStack {
    fn new() -> FloatStack {
        return FloatStack { data: [], count: 0 };
    }

    fn push(self, val: float) {
        self.data[self.count] = val;
        self.count = self.count + 1;
    }

    fn pop(self) -> float {
        self.count = self.count - 1;
        return self.data[self.count];
    }
}

Using nil for Flexible APIs

When a function needs to accept or return multiple types, the nil value provides a simple escape hatch. Callers check for nil and cast as needed.

fn get_or_nil(key: string, dict: Map) {
    let val = dict[key];
    if val == nil {
        return nil;
    }
    return val;
}

fn first_or_nil(items: int[]) {
    if items.count > 0 {
        return items[0];
    }
    return nil;
}

fn main() {
    let result = first_or_nil([10, 20, 30]);
    if result != nil {
        print("got: " + result);
    }
}

Struct Composition for Polymorphism

Rather than type parameterization, compose structs to build specialized versions of a data structure.

struct Pair {
    first: int;
    second: int;
}

impl Pair {
    fn sum(self) -&gt; int {
        return self.first + self.second;
    }
}

struct Config {
    name: string;
    value: int;
    pairs: Pair[];
}

fn main() {
    let cfg = Config {
        name: "demo",
        value: 42,
        pairs: [Pair { first: 1, second: 2 }],
    };
}

Future Plans

Full generics are planned for a future Braid version. The design will include:

  • Generic functions with type parameters: fn identity<T>(x: T) -> T
  • Generic structs: struct Option<T> { value: T; }
  • Generic constraints via future trait system
  • Monomorphization at compile time

The Hindley-Milner type checker already supports type variables and unification, which lays the groundwork for proper generics in the next iteration.