10. Generic Programming¶
10.1 Type Parameters¶
Type parameters allow functions, structs, and traits to work with multiple types.
Generic Syntax: <T> where T is a type parameter
Examples:
// Generic struct
(T T --) { x: y: } ::Point<T> struct
// Generic union
(T --) { Some(T) None } ::Option<T> union
// Generic trait
{
(Self T -- Self) append:
} ::Container<T> trait
Type Parameter Constraints:
When operations are performed on type parameters, they must be constrained by traits:
// Unconstrained - no operations on T
(T -- T) { } ::identity fn
// Constrained - T must support multiplication
(T:Multiplyable -- T) { dup * } ::square fn
Multiple Type Parameters:
(T E --) { Ok(T) Err(E) } ::Result<T E> union
10.2 Generic Functions¶
Generic functions work with multiple types by using trait constraints in their type tuples.
Syntax: (trait_constraints -- outputs) { body } ::name fn
Examples:
// Generic identity - works with any type (no operations, no constraint needed)
(T -- T) { } ::identity fn
// Requires Addable trait
(Addable Addable -- Addable) {
+
} ::add_values fn
// Requires Number trait
(Number -- Number) {
dup 0 > { } { 0 swap - } if
} ::abs fn
// Multiple constraints
(Number Number -- Number) {
dup * swap dup * + // a² + b²
} ::pythagorean fn
Type Inference: The compiler infers the actual type from usage:
5 identity // T inferred as i64
"hello" identity // T inferred as String
3 4 add_values // Addable inferred as i64
10.3 Generic Data Structures¶
Structs and unions can be generic over type parameters:
Generic Structs:
// Point is generic over coordinate type
(T T --) { x: y: } ::Point<T> struct
// Use with different types
3.0 4.0 Point // Point<f64>
3 4 Point // Point<i64>
// Multiple type parameters
(T U --) { first: second: } ::Pair<T U> struct
5 "hello" Pair // Pair<i64 String>
Generic Unions:
// Option is generic over contained type
(T --) { Some(T) None } ::Option<T> union
42 Option::Some // Option<i64>::Some
"text" Option::Some // Option<String>::Some
Option::None // Option<T>::None (T inferred from context)
// Result with two type parameters
(T E --) { Ok(T) Err(E) } ::Result<T E> union
Nested Generics:
// Array of Options
[Option::Some Option::None] // Array of Option<T>
// Option of array
[1 2 3] Option::Some // Option<Array<i64>>
10.4 Generic Traits¶
Traits can be generic, allowing them to describe behavior parameterized over types.
Generic Trait Syntax:
// Container generic over element type
{
(Self T -- Self) append:
(Self -- T) pop:
} ::Container<T> trait
// Map generic over key and value types
{
(Self K -- V) get:
(Self K V -- Self) insert:
} ::Map<K V> trait
Generic Trait Inheritance:
When inheriting from generic traits, you must either:
- Make the inheriting trait similarly generic
- Specify concrete types for the generic parameters
// Inheriting trait is also generic
[ ::Container<T> ] ::Stack<T> inher
{
(Self -- T) peek:
} ::Stack<T> trait
// Inheriting trait specifies concrete type
[ ::Container<i32> ] ::IntStack inher
{
(Self -- i32) peek:
} ::IntStack trait
// Multiple generic inheritance
[ ::Selectable<T> ::Sized ::Sliceable ] ::ArrayOf<T> inher
{ } ::ArrayOf<T> trait
10.5 Type Parameter Enforcement¶
Current Behavior: Type parameters are currently suggestions when parsing code blocks. The compiler does not yet enforce that type parameters actually constrain how operators and functions act at parse time.
Example:
// Currently no error even without Multiplyable constraint
(T -- T) { dup * } ::square fn
// Should require constraint
(Multiplyable -- Multiplyable) { dup * } ::square fn
Future Enhancement: See Appendix F for planned type parameter enforcement at parse time.