Type Parameters
Type parameters make it possible for routines to be type polymorphic, i.e., to be applied to values of different types. This means that whenever a routine with type parameters is called, actual type parameters have to be provided in addition to the actual value arguments.
The declared routine is essentially just a template that will be replicated and specialized for all the actual type parameters it is used with. This means that there is not runtime cost for passing type parameters, actual type parameter values only exist at compilation time.
Type parameters always precede value arguments in the declaration of a routine as well as in a call.
Basic Type Parameters
The following example implements the arithmetic mean of two values of a
numeric type that is provided as the type parameter N. The type
parameter N is constraint with the type numeric,
which means that the actual type parameters must inherit from the constraint
type.
The mean function can then be called using any numeric types such
as i32, f64 or num.complex f64:
Type parameters turn a feature into a template for all the variants given by
the actual types provided by the callers. The compiler will create specialized
versions of every combination of actual type parameters provided. In the
previous example, the declaration of mean with type parameters is
essentially short-hand for the declaration of three features operating on
different types as shown here:
Type inference for Type Parameters
Type parameters that are used within types of value arguments do not have to be given explicitly in a call. Instead, these type parameters can be omitted and inferred from the actual value arguments.
Consequently, the actual type parameters in the previous example are not
required, instead of mean f64 3.14 2.18, one can write mean
3.14 2.18, omitting the f64 that is derived from the float
constants 3.14 and 2.18:
Note that for a call to a routine that expects several type parameters, either all type parameters have to given or all of them have to be omitted. It is not possible to omit only some type parameters.
Free Types
The declaration of type parameters can be omitted to obtain a more concise and
readable feature declaration. If it is omitted, an undeclared type name
like N will be converted into a type parameter automatically. If
a constraint like : numeric is needed, that constraint must be
added to the first occurrence of that type N : numeric, while
later uses of that type N must not have a constraint. Such a
type is called a free type.
Free types will be added to as type parameters in the order they occur in the feature's signature. It is possible to use both, declared type parameters and free types. In this case, the free types will be added as type parameters after the declared type parameters.
Here is the example from above using a free type N : numeric:
Type Place Holder _
Anonymous Free Types
In case a free type is required only once, it can be made anonymous
suing _ as its name. In the previous example, this is possible
if we omit the result type and infer it from the implementation as follows:
Note that _ is a place holder for any name, repeated uses
of _ will be different types. Consequently, the following
example using _ twice, as type of a and as type
of b, will result in two different and incompatible anonymous
type parameters. So the following code will result in an error:
Inference of Subset of Type Parameters
Another use of _ as a type place holder is to force inference of a
subset of the type parameters.
The following example has two type parameters, A
and B. We might want to specify the actual type
for A explicitly, while the result type of the function argument
can be inferred. We can achieve this by providing an actual type
parameter u64 for A and leaving the type
of B for type inference using _:
Note that not providing a type here will result in i32 being the
inferred type which results in an overflow in the second call
to apply.