YREA-SLS/docs/generic_programming.md

4.0 KiB

Title Prev Next
10 Generic Programming Trait System Advanced Topics

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:

  1. Make the inheriting trait similarly generic
  2. 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.