In and out type variant of Kotlin

Elye
Elye
Dec 28, 2017 · 4 min read

If you ever defined generic in Kotlin, you’ll notice many a times, it would propose to use the in or out keyword to define the generic. It puzzles me at a start on when which is used, and for what.

Formally, this is a way to define contravariance and covariant. It took me a while to learn about it. I’ll dive in here to explain what how I understand and memorize their different.

In & Out easily remembered

If your generic class only use the generic type as output of it’s function/s, then out is used i.e.

interface Production<out T> {
fun produce(): T
}

I call it production class/interface, as it is mainly to produce output of the generic type. Hence very simple one could remember

produce = output = out.

If your generic class only use the generic type as input of it’s function/s, then in is used i.e.

interface Consumer<in T> {
fun consume(item: T)
}

I call it consumer class/interface, as it is mainly consuming the generic type. Hence very simple one could remember

consume = input = in.

In the event one generic class uses the generic type as input and output to it’s function, then no in or out is used. It is invariant.

interface ProductionConsumer<T> {
fun produce(): T
fun consume(item: T)
}

Why use In and Out?

Well, now you could easily remember when in and out is stated, what is their significance? Before we go there, let’s define burger class object. It is a fastFood, which is a type of food.

The simple class hierarchy as below.

open class Food
open class FastFood : Food()
class Burger : FastFood()

Looking at the genericProduction interface defined above, let’s further expand them to produce food, fastfood and burger as below

class FoodStore : Production<Food> {
override fun produce(): Food {
println("Produce food")
return Food()
}
}

class FastFoodStore : Production<FastFood> {
override fun produce(): FastFood {
println("Produce fast food")
return FastFood()
}
}

class InOutBurger : Production<Burger> {
override fun produce(): Burger {
println("Produce burger")
return Burger()
}
}

Now, lets have Food Production holders, we could assigned all of them to it

val production1 : Production<Food> = FoodStore()
val production2 : Production<Food> = FastFoodStore()
val production3 : Production<Food> = InOutBurger()

Either a burger or fastFood production, is still a food production. Hence

For 'out' generic, we could assign a class of subtype to class of super-type

If we change to below, it would error out, because food or fastFood is not just a burger production.

val production1 : Production<Burger> = FoodStore()  // Error
val production2 : Production<Burger> = FastFoodStore() // Error
val production3 : Production<Burger> = InOutBurger()

Now, looking at the genericConsumer interface defined above, let’s further expand them to consume food, fastfood and burger as below

class Everybody : Consumer<Food> {
override fun consume(item: Food) {
println("Eat food")
}
}

class ModernPeople : Consumer<FastFood> {
override fun consume(item: FastFood) {
println("Eat fast food")
}
}

class American : Consumer<Burger> {
override fun consume(item: Burger) {
println("Eat burger")
}
}

Now, lets have Burger Consumer holders, we could assigned all of them to it

val consumer1 : Consumer<Burger> = Everybody()
val consumer2 : Consumer<Burger> = ModernPeople()
val consumer3 : Consumer<Burger> = American()

Here, a burger consumer is an American, who is also part of ModernPeople, who is part of Everybody. Hence

For ‘in' generic, we could assign a class of super-type to class of subtype

If we change to below, it would error out, because consumer of Food although could be American or ModernPeople, it is not just American or just ModernPeople.

val consumer1 : Consumer<Food> = Everybody()
val consumer2 : Consumer<Food> = ModernPeople() // Error
val consumer3 : Consumer<Food> = American() // Error

Given the above, another to know when to use what is, for

SuperType could be assigned subtype, use IN

SubType could be assigned to SuperType, use OUT

I hope you appreciate this post and it’s helpful for you. Do share with others.

You could check out my other interesting topics here.

Follow me on medium, Twitter or Facebook for little tips and learning on Android, Kotlin etc related topics. ~Elye~

Mobile App Development Publication

Sharing Mobile App Development and Learning

Elye

Written by

Elye

Passionate about learning, and sharing mobile development and others https://twitter.com/elye_project https://www.facebook.com/elye.proj

Mobile App Development Publication

Sharing iOS, Android and relevant Mobile App Development Technology and Learning

Elye

Written by

Elye

Passionate about learning, and sharing mobile development and others https://twitter.com/elye_project https://www.facebook.com/elye.proj

Mobile App Development Publication

Sharing iOS, Android and relevant Mobile App Development Technology and Learning

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store