1. 무공변성

open class Alcohol
class Soju : Alcohol()

interface Drinker<T> {
    fun drink()
}

fun varianceTest(input: Drinker<Alcohol>){
    input.drink()
}

fun main() {

    val alchol: Drinker<Alcohol> = object:Drinker<Alcohol>{
        override fun drink(){
            println("Drink!")
        }
    }

    val soju: Drinker<Soju> = object:Drinker<Soju>{
        override fun drink(){
            println("Drink Soju!")
        }
    }

    // Success
    println(varianceTest(alchol)) // Drink!

    // Error
    println(varianceTest(soju)) // Type mismatch: inferred type is Drinker<Soju> but Drinker<Alcohol> was expected

}

2. 공변성

open class Alcohol
class Soju : Alcohol()

interface Drinker<T> {
    fun drink()
}

fun varianceTest(input: Drinker<out Alcohol>){ // out keyword 추가
    input.drink()
}

fun main() {

    val alchol: Drinker<Alcohol> = object:Drinker<Alcohol>{
        override fun drink(){
            println("Drink!")
        }
    }

    val soju: Drinker<Soju> = object:Drinker<Soju>{
        override fun drink(){
            println("Drink Soju!")
        }
    }

    val any: Drinker<Any> = object:Drinker<Any>{
        override fun drink(){
            println("Drink Any!")
        }
    }

    // Success
    println(varianceTest(alchol)) // Drink!

    // Success
    println(varianceTest(soju)) // Drink Soju!

    // Error
    println(varianceTest(any)) //Type mismatch: inferred type is Drinker<Any> but Drinker<out Alcohol> was expected

}

3. 반공병성

open class Alcohol
class Soju : Alcohol()

interface Drinker<T> {
    fun drink()
}

fun varianceTest(input: Drinker<in Alcohol>){ // in keyword 추가
    input.drink()
}

fun main() {

    val alchol: Drinker<Alcohol> = object:Drinker<Alcohol>{
        override fun drink(){
            println("Drink!")
        }
    }

    val soju: Drinker<Soju> = object:Drinker<Soju>{
        override fun drink(){
            println("Drink Soju!")
        }
    }

    val any: Drinker<Any> = object:Drinker<Any>{
        override fun drink(){
            println("Drink Any!")
        }
    }

    // Success
    println(varianceTest(alchol)) // Drink!

    // Error
    println(varianceTest(soju)) // Type mismatch: inferred type is Drinker<Soju> but Drinker<in Alcohol> was expected

    // Success
    println(varianceTest(any)) // Drink Any!

}