Generics
Function Generics
Type parameters can be defined by appending <T> immediately after the function name.
fn func<T>( val:T ): List<T> {
return [ val ];
}
let l1 = func( 10 ); // List<int>
let l2 = func( "abc" ); // List<str>
func<int>(10).
Class Generics
Append <T> immediately after the class name.
class Box<T> {
let val:T;
pub fn __init( val:T ) { self.val = val; }
pub fn get(): T { return self.val; }
}
let b = new Box( 100 ); // Box<int>
※ Note: Interfaces do not support Generics.
Type Parameter Constraints
By using the format <T:Constraint>, you can enforce that the type parameter inherits from
a specific class or implements a specific interface.
interface Val {
pub fn getValue(): int;
}
fn printVal<T:(Val)>( obj:T ) {
print( obj.getValue() ); // T implements Val, so it is callable
}
Constraints are also mandatory when creating a Mapping-capable Generics class.
class Model<T:(Mapping)> extend (Mapping) {
let data:T;
}
Without the T:(Mapping) above, it may not meet the implementation requirements of the Mapping
interface (all members must be Mapping-capable), resulting in a compilation error.
Method Generics
It is also possible to have individual type parameters for class methods.
class Test {
pub fn convert<T>( val:T ): str {
return "val: %s" (val);
}
}
Generics and Mutability
The type parameter T can be decorated at the time of declaration to control Mutability and
Nilability.
fn func<T>( val:T ): &T { return val; } // Returns an immutable T
fn func2<T>( val:T! ): T { return unwrap val; } // Receives a Nilable argument and returns a Non-nil value
! to the definition of the type parameter itself, like
<T!>.Specify it at the point of use, like
func<T>( val:T! ).