Type variances are a topic which most Java developers don't usually think about, but which can take some getting used to for those transitioning into languages which do make heavy use of them, like Scala.
There are three possible kinds of type variance
Recall that, in Scala, the notation
T <: S means that
extends or "subclasses"
T >: S means the converse -- that
S extends or subclasses
You may notice that
T >: S means the same as
S <: T, so why are there two different ways to say this? Well, you might want to define both an upper (
<:) and a lower (
>:) bound for your type. For example, if you wrote a class hierarchy that mirrored taxonomic ranks, you might want a type that is larger than
Species, but less than
Order, in which case you would write
Genus <: T <: Family.
You can think of
T <: S as meaning "
T is a type which is less than or equal to type
S" (in a subclassing / extending sense), while
T >: S means that "
T is greater than or equal to type
S". Since there are no taxonomic ranks between
Genus <: T <: Family means that type
T can be either
It's important to remember that when we talk about variance, we're talking about the types themselves, but also the "container types" which are parameterized by them.
What this means is that you can't talk about type variance without some parameterized type like
Map[K, +V]. We're interested in the parameterized types
Map, as they relate to their type parameters.
A parameterized type is invariant in its type parameter if there is no subclassing relationship when using different type parameters. For example, in Scala,
Set[A] is invariant in its type parameter
A. This means that
A <: B => Set[A] <: Set[B] is false A >: B => Set[A] >: Set[B] is false A <: B => Set[A] >: Set[B] is false A >: B => Set[A] <: Set[B] is false
In other words, no matter the relationship between
B, you cannot substitute a
Set[A] for a
Set[B] and vice versa. A
Set[String] is not a
Set[Any], for example, and a
Set[Numeric] is not a
If you're coming from a Java background, this is the variance you're probably most familiar with. Java was initially developed without generics (no type parameters!), so invariance was really the only solution.
A parameterized type is covariant in its type parameter if there is a parallel subclassing relationship when using different type parameters. For example, in Scala,
List[+A] is covariant in its type parameter
+A. (That's what the
+ means before the generic type
A.) This means that
A <: B => List[A] <: List[B] is true A >: B => List[A] >: List[B] is true A <: B => List[A] >: List[B] is false A >: B => List[A] <: List[B] is false
This is the more "intuitive" type variance, in my opinion. In this case, we might have a subclassing relationship like
Dog <: Animal, because a
Dog is a kind of
Animal. In that case, a
List[Dog] <: List[Animal] because a list of dogs is a kind of list of animals.
Wherever we require a
List[Animal], we can provide a
List[Dog] <: List[Animal] (read as "
Dog is a kind of
Contravariance is the "opposite" of covariance. A parameterized type is contravariant in its type parameter if there is an anti-parallel subclassing relationship when using different type parameters. For a parameterized type which is contravariant in its type parameter, the following relationships hold
A <: B => List[A] <: List[B] is false A >: B => List[A] >: List[B] is false A <: B => List[A] >: List[B] is true A >: B => List[A] <: List[B] is true
This one is a bit more difficult to explain.
Imagine we have a parameterized
Teacher[-S] class, where
S gives the
Teacher is qualified to teach. The
- indicates that
Teacher is contravariant in its type parameter
As for the
S, we might say that
TypeVariance is a kind of programming concept
TypeVariance <: ProgrammingConcept
...both of which are
Subjects which our
Teacher might teach.
Teacher is qualified to teach
ProgrammingConcepts, she must also be qualified to teach
TypeVariance (otherwise, she wouldn't be qualified to teach
In other words, wherever we require a teacher who is qualified to teach
TypeVariance, we can substitute a teacher who is qualified to teach
ProgrammingConcepts in general
Teacher[ProgrammingConcept] <: Teacher[TypeVariance]
TypeVariance is a kind of
ProgrammingConcepts is a
Top comments (0)