Covariance, Contravariance, and Invariance — What do they mean? (Part 1)

In Kotlin, Java; and a little bit of generics too.

Ben Daniel A.
AndroidPub
2 min readMay 13, 2019

--

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.

This means that a BabyChild is a GrandParent (well, maybe eventually), shhh don’t think too much.

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.

The type `TaxPayer<Parent>` is Covariant in this context.

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.

The type `Adult<Parent>` is Contravariant in this context.

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.

The type `Customer<Parent>` is Invariant in this context.

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.

The type `Person<Parent>` is Bivariant in this context.

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.

--

--