LEVIATHAN v962456e · 962456eee1

Types

Generics

Generic classes and functions, how type arguments are inferred or given explicitly with ::<T>, invariance, T::member and type constructors.

since 0.1.0-alpha.1linuxwindowswasm

Description

A class, a function or a method can take type parameters: class Box<T>, R identity<R>(R x), U map<U>(...). In a type, an instantiation is written Name<T1, ...>, as in Box<int>.

The compiler infers type arguments, in this order:

  1. from the types of the constructor or call arguments, including through containers (an Array<U> parameter against an Array<int> argument gives U = int);
  2. from the target type of the initializer, assignment or return that receives the result.

When inference is not enough, or you want to state the types, give them at the call with ::<...>: Box::<int>(), identity::<string>("x"), items.remap::<string>(fn).

Generic class and functions

class Box<T> {
    T item;
    T get() => this.item;
    U map<U>((T) => U f) => f(this.item);
}

R identity<R>(R x) => x;

Box<int> a = Box(5);
console.writeln(a.get());
console.writeln(a.map((n) => "n=${n}"));
Box<string> b = Box::<string>("hi");
console.writeln(b.get());
console.writeln(identity(41) + 1);
console.writeln(identity::<string>("x"));
void demo() {
    var f = identity::<int>;
    console.writeln(f(7));
}
demo();
5
n=5
hi
42
x
7

Rules

Writing and inferring type arguments.

  • A type position uses angle brackets: Name<T1, T2>. Instantiations nest: Array<Array<int>>.
  • A call uses the turbofish, callee::<T1, ...>(args). f<T>(x) written without :: is a comparison, never a generic call.
  • The turbofish with no argument list, identity::<int>, is a pinned reference to the generic function as a value. An unpinned reference, var f = identity;, is a compile error that suggests the turbofish.
  • An explicit list is all-or-nothing and exact. Its length must equal the generic arity of the constructor, function or method: Box::<int, int>(1) and a one-argument list for a two-parameter function are errors.
  • An explicit list needs a declared function, method or constructor. It cannot be applied to a closure or another function value.
  • Receiver class arguments are independent of a method's explicit list: items.remap::<string>(fn) supplies only the method's parameter.

Variance.

  • Generics are invariant: a Box<int> is not a Box<float>, even though int converts to float.
  • The raw form, the generic name without arguments (Box), is compatible with any instantiation of the same generic.

T::member.

  • Inside a generic function, the left side of :: may be one of that function's own type parameters: A::FromInt(n) calls the labeled constructor FromInt of whatever type A is at the call.
  • The member is checked for each concrete type used. If the type lacks the member, the error names the type and points to both the A::member use and the call that instantiated it.
  • T:: works only for type parameters of the function. A class-level parameter is rejected: "'T' is a class-level type parameter".

Type constructors.

  • A type parameter may stand for a generic type that takes an argument, written F<A>. Inference binds F to the generic name: F<A> against Array<int> gives F = Array and A = int, and the result type F<B> keeps the container.
  • This is an advanced idiom. Prefer ordinary methods for everyday code.

Examples

T::member and a type constructor:

T::member and a type constructor

class Meters {
    int n = 0;
    new FromInt(int v) { this.n = v; }
}

class Wrapper<T> {
    T item;
    new Of(T v) { this.item = v; }
}

A decode<A>(A witness, int n) => A::FromInt(n);
F<B> mapIt<F, A, B>(F<A> c, (A) => B fn) => c.map(fn);

Meters m = decode(Meters(), 12);
console.writeln(m.n);
Wrapper<string> w = Wrapper::Of::<string>("lab");
console.writeln(w.item);
Array<int> d = mapIt([1, 2, 3], (n) => n * 2);
console.writeln(d);
12
lab
[2, 4, 6]

Notes

Not supported: using T::member where T is a class-level type parameter.

See also

  • Type expressions — How a type is written: names, qualified names, generic instantiations, unions, optionals and function types.