Generics (v0.2.1)
Compile-time generic templates for functions and structures.
Overview
Generics let one function or struct work with more than one type. The compiler creates concrete versions from the types used at call sites.
Type arguments are written in square brackets, such as add[s32](1, 2) or Vector[u8]. This keeps the chosen type visible.
Use generics for repeated patterns like containers or small helpers. Avoid using them when a concrete type would be clearer.
Primary source: syntax/generics/generics.md
Syntax Signatures
fn add[T](a: T, b: T) T @public {
return a + b;
}
struct Vector[T] @public {
data: ptr[T],
length: usize,
capacity: usize,
}
Behavior and Use
A generic instantiation behaves like ordinary concrete code after compilation.
Generic functions should make their assumptions obvious from the operations they use on T.
Best Practices
- Write type arguments explicitly where it helps readers understand the call.
- Use generics for repeated patterns, not to hide unrelated behavior.
- Be clear about who owns memory in generic containers.
Instantiation
Generic code is turned into concrete code for the types used by the program.
- Function type arguments are written after the function name, for example add[s32](1, 2).
- Struct type arguments are written after the struct name, for example Vector[u8].
- Once instantiated, generic code follows the same type-checking and code generation rules as non-generic code.
Constraints by Use
Current generic assumptions are expressed by the operations used inside the generic body.
- If a generic function adds two values, each concrete T must support that operation.
- If a generic container stores pointers or owns memory, document ownership at the API boundary.
- Prefer concrete types when only one type is expected. Generics should remove duplication, not hide intent.
Example
fn main() s32 @public {
var value: s32 = add[s32](20, 22);
var vec := new Vector[s32] {
data: nullptr,
length: 0,
capacity: 0
};
return value + (vec->length as s32);
}