Zith supports generic programming with both explicit and implicit type parameters, constrained via traits or type unions using the or keyword.
fn identity<T>(val: T): T { val }
struct Pair<T, U> {
first: T,
second: U,
}
fn serialize<T: Serializable + Printable, U: Clone>(val: T, ctx: U): string { ... }
When type parameters are omitted, the compiler infers constraints from usage at the call site:
fn add(a, b) { a + b } // Arithmetic implicitly required
fn print(val) { @println(val); } // Printable implicitly required
orThe or keyword specifies compile-time type constraints — a union of acceptable types dispatched at compile time:
type Number = i32 or f64 or bool;
fn convert<T: Number>(val: T): string {
// T must be one of i32, f64, or bool
// Specialised code generated for each
}
ℹ Contrast with union, where variants are separated by commas and dispatch happens at runtime (see Type System).
implement Pair<T, U> {
fn swap(self: lend) {
let tmp = self.first;
self.first = self.second;
self.second = tmp;
}
}
implement Vec<T> as Printable {
fn print(self) {
for (v in self) { @println(v); }
}
}
Zith compiles generics via monomorphisation: each unique combination of type arguments generates a specialised copy of the function or struct. This ensures zero-cost abstractions with no runtime dispatch overhead for generic code.
See also: Spec: Polymorphism
Next: Memory Model — NRA