코세라 강의 보는 중에
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 라고 부른다.
'프로그래밍 > Scala' 카테고리의 다른 글
[Slick] DateTime 로딩 시 오류. (0) | 2020.04.05 |
---|---|
Scala 로 뭔가 만들기 위해 필요한 것. (0) | 2020.03.18 |
akka 초반 간략정리. (0) | 2020.02.09 |
Typing Rules for Functions (0) | 2020.02.02 |
Covariant, Contravariant 그림으로 다시 정리 (0) | 2020.02.02 |
scala implicit keyword 관련 - 파라미터 (0) | 2019.11.17 |
[스칼라] Slick 오류 처리 (0) | 2017.03.26 |
[스칼라] 커링(Currying) - 아마도 첫번째 글. (0) | 2017.02.26 |