In and out type variant of Kotlin
Tags: kotlin
Published: 2020-09-19 14:53:29

 ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3dmw4upfy2e23rrq5v38.png)
If you ever defined generic in kotlin,you'll notice many a times,it would propose to use the <kbd>in</kbd> or <kbd>out</kbd>keyword to define the .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
##out(covariant type)

if your generic class only use the generic type as output of it's function/s,then <kbd>out</kbd> 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
<table><tr><td>produce = output = out</td></tr></table>
##In (contravariance type)
If your generic class only use the generic type as input of it's function/s,then <kbd>in</kbd> 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
<table><tr><td>consume = input = in</td></tr></table>
##Invariant Type
In the event one generic class uses the generic type as input and output to it's function,then no <kbd>in</kbd> or <kbd>out</kbd> 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  <kbd>in</kbd>and<kbd>out</kbd>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 bleow

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0uzxi4b1spesr6ko1vr0.png)
```
open class Food
open class FastFood : Food() 
class Burger : FastFood()
```
##Burger Production
Looking at the generic **Production** interface defined above,Let's further expand them to product *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 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()
```
##Burger Consumer
Now, looking at the generic **Consumer** 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* althought 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
```
#Another way to remember In and Out
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

</br>
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4whe0r6gh56hzcsqj01t.png)
[from > In and out type variant of Kotlin](https://medium.com/mobile-app-development-publication/in-and-out-type-variant-of-kotlin-587e4fa2944c)