Kind PolymorphismEdit this page on GitHub
Normally type parameters in Scala are partitioned into kinds. First-level types are types of values. Higher-kinded types are type constructors
Map. The kind of a type is indicated by the top type of which it is a subtype. Normal types are subtypes of
covariant single argument type constructors such as
List are subtypes of
[+X] => Any, and the
Map type constructor is
a subtype of
[X, +Y] => Any.
A type can be used only as prescribed by its kind. Subtypes of
Any cannot be applied to type arguments whereas subtypes of
[X] => Any
must be applied to a type argument, unless they are passed to type parameters of the same kind.
Sometimes we would like to have type parameters that can have more than one kind, for instance to define an implicit
value that works for parameters of any kind. This is now possible through a form of (subtype) kind polymorphism.
Kind polymorphism relies on the special type
scala.AnyKind that can be used as an upper bound of a type.
def f[T <: AnyKind] = ...
The actual type arguments of
f can then be types of arbitrary kinds. So the following would all be legal:
f[Int] f[List] f[Map] f[[X] => String]
We call type parameters and abstract types with an
AnyKind upper bound any-kinded types`.
Since the actual kind of an any-kinded type is unknown, its usage must be heavily restricted: An any-kinded type
can be neither the type of a value, nor can it be instantiated with type parameters. So about the only
thing one can do with an any-kinded type is to pass it to another any-kinded type argument.
Nevertheless, this is enough to achieve some interesting generalizations that work across kinds, typically
through advanced uses of implicits.
(todo: insert good concise example)
Some technical details:
AnyKind is a synthesized class just like
Any, but without any members. It extends no other class.
It is declared
final, so it can be neither instantiated nor extended.
AnyKind plays a special role in Scala's subtype system: It is a supertype of all other types no matter what their kind is. It is also assumed to be kind-compatible with all other types. Furthermore,
AnyKind is treated as a higher-kinded type (so it cannot be used as a type of values), but at the same time it has no type parameters (so it cannot be instantiated).
Note: This feature is considered experimental and is only enabled under a compiler flag