Invariance, Covariance, and Contravariance in Kotlin

In our earlier post, we talked about the Generics in Kotlin at a basic Level, If you missed it, I will suggest you can go ahead and read it through here.

In this blog post, we will be covering Invariance, Co-variance and Contra-variance and how these help us to code in Kotlin. At this time, It is very imperative that we are clear with the terms like Super class, Sub class and Sub type.

Let’s take this simple example:

Implementation 1:

In the above example, Color is my Superclass for the classes Black and Red and just for a check, Any is a superclass for Color and any other class defined in Kotlin. Black and Red are subclasses of Color class.

Relationship Representation among different classes

When we talk of subtypes, we generally refer it to the properties and behavior associated with the object of that class. By this definition, I may infer that Color class will have a single subtype, the instance given by its own self, but here is the twist.

It is not single but it will have two subType. One given by self and one inherited from Any class. For Black and Red class, they will have 3 subtypes, one from itself, one from Color class and one from Any class.

Let’s look at the below code and try to clear some more doubts:

Implementation 2:

If you will compile above code, it succeeds, that means we are able to assign a child class instance where a Super class instance was required. In OOPs Paradigm, it is possible because of the Liskov Substitution Principle, which emphasizes on Open/Closed Principle for a class.

Let’s look at another implementation:

Implementation 3:

So, this is the tricky part that the second line will not compile, however for a fact we know that Color is the Superclass of the Red Class and our implementation 2(based on the above fact) worked like a charm. Before pulling off the curtains over this suspense let’s look into one more example:

Implementation 4:

Awesome, Our code just compiled! Why? So, the reason is that the Arrays in Kotlin are by default defined as In-variant and Lists are defined as Co-variant and that is the reason our Implementation 3 failed and Implementation 4 succeeds.

When we are working with Generics in Kotlin, we always have to remember that by default there is no relationship between the types until defined explicitly i.e the relationship is In-variant. In kotlin, we use two keywords to develop a relationship which can be co-variant or contra-variant. Let’s have a look at each one of it:

  • IN (To make the relationship contra-variant)
  • OUT ( To make the relationship co-variant)

Let’s have a look at Co-variant(Out) type relationship:

Implementation 5:

Let’s look at the main function for above classes:

Implementation 6:

You might be aware now, why the above code, the last line in the Implementation 6 will not compile? Yes, because right now our Generic class School does not have any type of relationship i.e it has an invariant relationship. To make it co-variant let’s modify our implementation 5 first

So, we just added out keyword when compared with Implementation 5, rest everything remains the same. So with our change, we have defined a relationship where School<FinanceDepartment> has become subtype of School<Department>

So the following code works fine now:

At the same time, if we go back and have a look at Implementation 4, it is the very same reason that the List in Kotlin has been defined with out keyword hence a co-variant relationship is shared. Let’s have a quick sneak peek into List implementation as well:

Now, let’s have a look at the contra-variance ( In ) relationship. Firstly, let’s go through the following a set of lines:

In order to make the above code work, we will need to add the out keyword definition to our School definition. So let’s modify our implementation 5:

After modifying the above code, we will be able to execute the following set of lines successfully:

So, finally we can draw a conclusion from the following simple diagram, when you want to assign a subtype to a super type i.e make a relationship co-variant use IN Keyword and when you want to assign a super type to a subtype i.e make the relationship a contra-variant use OUT keyword.

In-Out Relationship

That’s all for this post, until the next one, stay tuned…

Leave a Reply

Your email address will not be published. Required fields are marked *