Generics & Bounds
Generics let one declaration work with multiple types. Generic parameters are written after the
declaration name. Type parameters use a name such as T; const generic parameters use
Name: const Type.
Generic Functions
Section titled “Generic Functions”Generic Types
Section titled “Generic Types”a: A and b: B state that these public regions have the same lifetime shape as their respective
type arguments. A generic field binding supplies one complete shape: @life(a) binds every lifetime
carried by A; it does not bind only the first one.
Type arguments may include suffixes:
Generic Initializer Inference
Section titled “Generic Initializer Inference”A generic nominal initializer may omit repeated type arguments when the declared target supplies the
same nominal type. _ creates an inference hole for only that argument:
The compiler solves each hole from the declared type, initializer arguments, and generic constraints. Explicit arguments are never overwritten. Omitting all constructor arguments requires a compatible expected nominal type; this deliberately fails because neither side provides one:
Value initializers and new owner initializers use the same inference rules.
Const Generic Parameters
Section titled “Const Generic Parameters”Const generic parameters are compile-time values:
Const generic names are value-level names. They can be used in expressions, but not as type names. The inline form lowers to the same canonical predicate as a leading constraint:
@where
Section titled “@where”@where(...) is a leading attribute:
Multiple constraints use commas:
Intersection bounds use &:
Declaration-Local Aliases
Section titled “Declaration-Local Aliases”@alias(Name = Type) creates a local type alias for the current declaration. The alias is visible
only in that declaration’s signature, constraints, members, and function body. It does not leak into
the module namespace:
Leading attributes are applied in source order. Generic parameters for the current declaration are
available before attributes are applied. Later attributes can use aliases introduced by earlier
@alias attributes, but earlier attributes cannot use aliases introduced later. One @alias(...)
can contain multiple comma-separated bindings. This is equivalent to splitting them into multiple
ordered @alias attributes:
Equality Constraints
Section titled “Equality Constraints”Generic parameter equality:
Use != to reject a concrete type shape:
_ inside a type shape is an anonymous placeholder. It does not introduce a generic name; it only
means that any type argument is accepted in that position. For example, _^ matches every owning
pointer type, and Vector<_> matches a Vector with any element type:
Use : for trait bounds. Use == or != for concrete type-shape matching:
Negative trait bounds use ! before the trait name:
Projected associated type equality uses T.[Trait].Assoc == Type:
Associated Type Bindings
Section titled “Associated Type Bindings”Trait bounds can bind associated types:
Mutable Generic Parameters
Section titled “Mutable Generic Parameters”Use the built-in Mutable bound when a type parameter must carry a type-level write capability:
Mutable currently matches T&! and T*!. Binding mutability such as Int value! is not a type
argument and therefore is not checked by generic bounds.
Errorable Returns
Section titled “Errorable Returns”Generic functions can return T@E in result position:
If the success value is optional, put ? on the success type:
Grammar Boundaries
Section titled “Grammar Boundaries”- Generic type parameters accept types. Const generic parameters accept compile-time values with an
explicit type, such as
N: const Int. @where(...)is written before the declaration, not after it.- Associated type projection constraints use the
T.[Trait].Name == Typeform.