Generic declarations, instantiation, and conformance
Grammar
Section titled “Grammar”TypeParameters = "<" identifier { "," identifier } ">" .TypeArguments = "<" Type { "," Type } ">" .GenericDeclaration = ( "struct" | "class" | "union" | "ref" "union" | "interface" | "func" | "static" ) identifier [ TypeParameters ] .ClosedType = identifier TypeArguments .E# generics are reified: a closed instantiation contains its actual type arguments in CLR metadata, rather
than erasing them to object. Thus Box<int> and Box<string> are distinct closed types, and fields/methods
use their substituted type directly.
struct Pair<A, B> { first: A, second: B }let p = Pair<int, string> { first: 1, second: "one" }Type identity includes name and arity. Cell<A> and Cell<A, B> are separate declarations, while a
non-generic static Result facet can coexist with struct Result<T, E>.
A generic method has its own type parameters in addition to any on its containing type. Conformance is
nominal after type-argument substitution: class Box<T> : IBox<T> implements the closed IBox<T> contract,
not every IBox<U>. E# generic interfaces are invariant because the language has no variance declaration
syntax; imported BCL interfaces retain their CLR variance.
A generic companion facet repeats the owner’s open parameter list and shares its name and arity:
struct Wrapper<T> { value: T }
static Wrapper<T> { func ==(left: Wrapper<T>, right: Wrapper<T>) -> bool = left.value == right.value func !=(left: Wrapper<T>, right: Wrapper<T>) -> bool = left.value != right.value}The operator itself cannot declare another type-parameter list. At a closed use such as Wrapper<int>,
the owner’s T is substituted into the exact operator signature and the emitted call targets the closed
generic host.