Unit content
Variance in parameterized and function types
Variance describes how a subtype relationship between component types changes when those types appear inside a larger type constructor.
Suppose
$$Cat<:Animal.$$
A read-only container can often be covariant:
$$Box(Cat)<:Box(Animal),$$
because anything read from a Box(Cat) is also an Animal.
A write-only consumer is naturally contravariant. A function that can accept every Animal can certainly be used where only Cat values will be supplied.
Function types combine both directions. If
$$S_1<:T_1$$
and
$$T_2<:S_2,$$
then
$$T_1\to T_2 <: S_1\to S_2.$$
Function arguments are contravariant; return values are covariant. A replacement function must accept at least everything the caller may provide and may promise a more specific result.
Mutable references are commonly invariant. Treating Ref(Cat) as Ref(Animal) would allow writing a Dog into storage later read as a Cat.
Variance is therefore not arbitrary annotation syntax. It follows from how values of a parameterized type are produced and consumed, and it explains many otherwise surprising generic-subtyping restrictions.