Generics & Bounds
Generics let one declaration work with multiple types. Generic parameters are written after the declaration name.
Generic Functions
Section titled “Generic Functions”T id<T>(T value) { return value;}
Int a = id<Int>(42);_ b = id(42);Generic Types
Section titled “Generic Types”struct Pair<A, B> { A first; B second;}
Pair<Int, UInt8[]> pair = Pair<Int, UInt8[]> { first: 1, second: "one",}Type arguments may include suffixes:
Pair<Int?, UInt8[]> maybe_pair;Pair<Int!, Int[3]^> mutable_and_owner;@where
Section titled “@where”@where(...) is a leading annotation:
@where(T: Numeric)T add<T>(T left, T right) { return left + right;}Multiple constraints use commas:
@where(T: Hashable, U: Equatable)Pair<T, U> make_pair<T, U>(T left, U right);Intersection bounds use &:
@where(T: Hashable & Equatable)UInt hash_key<T>(T value);Equality Constraints
Section titled “Equality Constraints”Generic parameter equality:
@where(T == UInt8)Int use_byte<T>(T value);Projected associated type equality uses T.[Trait].Assoc == Type:
@where(T.[Iterable].Item == UInt8)Int count_bytes<T>(T value);Associated Type Bindings
Section titled “Associated Type Bindings”Trait bounds can bind associated types:
@where(T: Iterable<Item = UInt8>)Int count<T>(T value);Mutable Generic Parameters
Section titled “Mutable Generic Parameters”Top-level mutability can be expressed through a Mutable bound:
@where(T: Mutable)struct Slot<T> { T value;}
Slot<Int!> slot = Slot<Int!> { value: 1 }Errorable Returns
Section titled “Errorable Returns”Generic functions can return T@E in result position:
@where(T: Numeric)T@ParseErr parse_number<T>(UInt8[] text);If the success value is optional, put ? on the left side of @:
T?@ParseErr parse_optional<T>(UInt8[] text);Grammar Boundaries
Section titled “Grammar Boundaries”- Generic parameters accept types, not non-type parameters.
@where(...)is written before the declaration, not after it.- Associated type projection constraints use the
T.[Trait].Name == Typeform.