Covariance, Contravariance, and Invariance — What do they mean? (Part 1)
In Kotlin, Java; and a little bit of generics too.
In one of my previous posts, I talked about how I decided to understand the keywords and concepts behind the Kotlin language. I did this by providing a simple explanation of the inline
, noinline
and crossinline
keywords in Kotlin. Today I will try and explain some other concepts.
To do this, I will set up a simple inheritance structure.
Let’s get begin.
Covariance
This means that if we have a type T
, only type T
and subtypes of T
are allowed in this context.
For example, let us assume that there’s a tax on people without grand children, in this case we represent this with a covariant TaxPayer<Parent>
. This means that only a Parent
and a BabyChild
can pay this kind of tax, since they do not have grandchildren.
Contravariance
This means that if we have a type T
, only type T
and supertypes of T
are allowed in this context.
For example, only adults are allowed to drink beer (ideally), in this case we represent this with a Contravariant Adult<Parent>
. This means that only a Parent
and a GrandParent
can buy and drink beer, but not a BabyChild
.
Invariance
This means that if we have a type T
, only type T
is allowed in this context. No supertypes or subtypes of T
are allowed.
For example, if there’s an oddly specific special discount voucher for people who are parents and still have their own parents but have no grandchildren. Here, this is represented with an invariant Customer<Parent>
. This means that only a Parent
can use this voucher, but not a BabyChild
or a GrandParent
.
Bivariance (bonus)
This means that if we have a type T
, the type T
, its subtypes and supertypes are allowed in this context.
For example, when it comes to fun, everyone can have fun! Here, this is represented with a Person<Parent>
. This means that a BabyChild
, Parent
and GrandParent
can have fun.
Now that we have gotten the basics out of the way, let us dive deeper into what they really imply for in Kotlin and Java. I’ll be doing this in the second part of this post.
Special thanks to this Stack Overflow answer, this medium post and this blog post. They gave me different perspectives for this series.