yoshikit1996’s diary

日々勉強したことの備忘録です。

共変(covariant)と反変(contravariant)

Scalaのプログラムで[+A]とか[-A]というやつが出てきますが、これは変位指定アノテーションと言います。

次のプログラムにおいて、BがAを継承しているときに右辺を左辺に代入することができます。これを共変と言います。

val myClass: MyClass[A] = new MyClass[B]

次にAやBに具体的な型を当てはめた例を示します。

object Main extends App{
    
    class MyClass[+A](value: A) {
        val getValue: A = value
    }
    
    sealed trait Animal
    case class Cat(name: String) extends Animal
    
    val myClass: MyClass[Animal] = new MyClass[Cat](Cat("たま"))
    println(myClass.getValue) // Cat(たま)
}

[+A]という記号の意味は、おそらく、

[+A] = Aに何かを付け足したもの = Aを継承したもの

みたいな意味なんでしょうが、この記号に慣れるまでは、直感的な理解が難しそうです。
私は毎回「[+A]とはなんだ?Aに何かを付け足しものだ。それはつまりAを継承したやつだ。」っていうのを脳内でグチャグチャ考えています。

逆に反変の[-A]という記号の意味は、

[-A] = Aに何かを引いたもの = Aの継承元

といった感じでしょうか。

また、[B >: A]と書いた場合、Aを継承したBという意味になります。これはUMLのクラス図で描く継承の矢印と同じ向きに>記号が向いているので、分かりやすいと思いました。