336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

코세라 강의 보는 중에 


A <: B 이고 C[A] <: C[B] 인걸 Covariant 

A <: B 이고 C[A] >: C[B] 인걸 Contravariant 라고 한다.


Covariant 는 이미 알고있는 거고,

Contravariant 가 무슨소린지 도저히 모르겠어서, 구글링... 하다가 하나 발견... 4시간에 걸쳐 겨우 이해하고, 정리글을 남긴다. 


아래와 같이 클래스들이 있고, 함수 타입 한개를 선언한다.


그리고 몇가지 함수들을 선언한다.

class Animal {}

class Bird extends Animal {}
class Chicken extends Bird {}
class Duck extends Bird {}

object HelloWorld {
  type FunctorType[A] = (A => String) //함수타입 한개 선언

  val birdFunc : FunctorType[Bird] = { a => "Bird" }
  val animalFunc : FunctorType[Animal] = { a => "Animal" }
  val chickenFunc : FunctorType[Chicken] = { a => "Chicken"}
  val duckFunc : FunctorType[Duck] = { a => "Duck"}
}


이경우 클래스 관계는 


Animal <- Bird <- Chicken

Animal <- Bird <- Duck


이런 형식으로 된다. 다들 알다시피 


하지만 함수 아래와 같이 함수가 파라미터로 전달 될 때도, 다형성이 그대로 유지될까?

def test_contravariant(a: FunctorType[Bird]): Unit = {
    val ret1 = a(new Chicken);
    println(ret1)
    val ret2 = a(new Bird);
    println(ret2)
}



test_contravariant(animalFunc) 
test_contravariant(birdFunc) 
test_contravariant(chickenFunc)  //컴파일에러
test_contravariant(duckFunc)     //컴파일에러


맨 처음 봤을때는 의외의 결과였다. 그 전에 C++ JAVA 에서 써왔던 것과 반대로 나타났기 때문이다. 


내친김에 covariant 도 테스트 해본다. 


def test_covariant(a: Bird) : Unit = {
    println(a.toString)
}


예상한대로 결과가 나온다.


test_covariant(new Animal) //컴파일에러 test_covariant(new Bird) test_covariant(new Chicken) test_covariant(new Duck)


클래스 상속과 관련해서 생각을 다시 정리해본다. 


"

슈퍼클래스의 참조로 하위클래스의 객체를 생성하거나 파라미터로 전달해도 문제가 없는 이유는, 

하위클래스라고 해서 있던 public 함수/변수가 없어지거나 하지 않기 때문이다.

"


그리고 contravariant 예제를 다시한번 본다.


val animalFunc : FunctorType[Animal] = { a => "Animal" }
val birdFunc : FunctorType[Bird] = { a => "Bird" }
val chickenFunc : FunctorType[Chicken] = { a => "Chicken"}
val duckFunc : FunctorType[Duck] = { a => "Duck"}

def test_contravariant(a: FunctorType[Bird]): Unit = {
    val ret1 = a(new Chicken);
    println(ret1)
    val ret2 = a(new Bird);
    println(ret2)
}


test_contravariant 의 파라미터로 chickenFunc 나 duckFunc 를 넘기게 되면, 


Chicken 클래스에는 있는 public 함수지만, Bird 클래스에는 없는 public 함수가 있을 수 있다.

Duck 클래스에는 있는 public 함수지만, Bird 클래스에는 없는 public 함수가 있을 수 있다.


하지만 animalFunc 을 test_contravariant 로 넘기게 되면,

Animal 클래스에 있는 모든 public 함수는 Bird 클래스에 있다.


이때문에 FunctorType[슈퍼클래스] 에 대해서는 다형성이 일어나지만,

FunctorType[하위클래스] 에 대해서는 다형성이 일어나지 않는다. 

즉, 상속 관계가 역전이 된다. 


이런 경우가 A <: B 이고 C[A] >: C[B] 이며, 

이를 contravariant 라고 부른다. 




블로그 이미지

캡틴토마스

그저 걷고 있는거지...

,