Programming Fundamentals › Type Systems
Covariance and Contravariance
How subtyping of generic types follows their type parameters.
Also known as: variance, covariant, contravariant
If Dog is a subtype of Animal, is List<Dog> a subtype of List<Animal>? Variance answers how subtyping of a generic type follows from its type parameters, and the answer is “it depends on what the container does”.
- Covariant — follows the parameter in the same direction:
Producer<Dog>is aProducer<Animal>, because a producer of dogs is a producer of animals. You can safely read from it. - Contravariant — follows in the opposite direction:
Consumer<Animal>is aConsumer<Dog>, because something that accepts any animal can accept a dog. You can safely write to it. - Invariant — neither:
List<Dog>is not related toList<Animal>at all.
A useful rule is “producers covariant, consumers contravariant”. It’s often written PECS — Producer Extends, Consumer Super — for languages that express variance at the use site.
The classic mistakes:
- Assuming mutable containers are covariant. They can’t be. If
List<Dog>were aList<Animal>, you could add anAnimalthat isn’t a dog, and a later reader expecting a dog would break. This is the unsound hole in old languages’ array covariance. - Fighting the compiler. Error messages about “expected
Animal, foundDog” are usually the compiler stopping you from an unsound assignment. The fix is the right annotation (or a call-site wildcard), not a cast that defeats the check. - Mixing up the directions. Covariance and contravariance are easy to swap. Anchor with the producer/consumer rule: reading narrows (covariant), writing widens (contravariant).
- Over-tuning. Most code never needs explicit variance. Reach for it when designing library types or generic APIs; otherwise let the language’s defaults do their job.
Variance is why interfaces and function types behave the way they do in structural type systems, and why the same generic class can accept different parameter types depending on whether you’ll pass values in or read them out.