Generics
Mux supports generics with type parameters and interface bounds, similar to Go and Rust.
Generic Functions
Functions can be generic over type parameters:
Type Constraints
Use the is keyword to constrain type parameters to specific interfaces:
Multiple Type Parameters
Multiple Bounds (AND Semantics)
Type parameters can have multiple constraints:
Generic Classes
Classes can be generic over type parameters:
Generic Classes with Multiple Type Parameters
Built-in Interfaces
Mux provides built-in interfaces for common operations:
| Interface | Description |
|---|---|
Stringable | Types that can be converted to string (via .to_string() method) |
Equatable | Types that support == and != operators |
Comparable | Types that support <, <=, >, >= operators |
Hashable | Types that can be used as keys in sets and maps |
Error | Types that can be used as result<T, E> errors (via .message() method) |
Operator Mapping
a + b- Works for types with native support (int, float, string, list, map, set)a > b- Works for types with native support (int, float, string, char)a == b- Works for all types
Primitives and Interfaces
| Type | Implements |
|---|---|
int | Stringable, Equatable, Comparable, Hashable |
float | Stringable, Equatable, Comparable, Hashable |
string | Stringable, Equatable, Comparable, Hashable, Error |
bool | Stringable, Equatable, Hashable |
char | Stringable, Equatable, Comparable, Hashable |
result<T, E> requires E to implement Error.
Implementing Interfaces for Custom Types
Custom types can implement interfaces to work with generic functions:
Generic Functions with Collections
Monomorphization
Mux uses compile-time monomorphization for generics - specialized code is generated for each type instantiation:
How Monomorphization Works
- Type inference: Determine concrete types from function arguments
- Name generation: Create unique identifier:
FunctionName$$Type1$$Type2$$ - Type substitution: Replace type parameters with concrete types
- Code generation: Emit specialized function body
- Caching: Store generated methods to avoid regeneration
Benefits
- Zero runtime cost: No boxing, no vtables, no type checks
- Static dispatch: Methods resolved at compile time
- LLVM optimization: Each specialization can be fully optimized
Tradeoff
- Increased intermediate code size and compilation time: One copy per type combination
Type Inference in Generics
Type parameters can often be inferred from context:
However, when ambiguous, explicit types are required:
Generic Enums
Enums can be generic:
See Enums and Error Handling for more details.
Constraints and Bounds
Single Constraint
Multiple Constraints (AND)
Type T must implement all specified interfaces.
Best Practices
- Use type constraints - Specify what operations are needed
- Prefer interface bounds over concrete types - More flexible
- Leverage monomorphization - No runtime overhead for generics
- Use descriptive type parameter names -
T,U,K,Vfor simple cases - Explicit types when ambiguous - Helps readability
- Keep generic functions simple - Complex logic harder to debug
- Document constraints - Make requirements clear
See Also
- Functions - Generic functions
- Classes - Generic classes
- Enums - Generic enums
- Error Handling - optional<T> and result<T, E>