9.7. Ograniczenia typów kowariantnych i kontrawariantnych
Nie każdy typ ogólny może być kowariantny i nie każdy może być kontrawariantny ze względu na określone parametry typu.
Plik ReaderWriter1.scala: class ReaderWriter[+T](private var content: T) { def read: T = content def write(x: T) { content = x } }
Plik ReaderWriter2.scala: class ReaderWriter[-T](private var content: T) { def read: T = content def write(x: T) { content = x } }
Przykłady z plików ReaderWriter1.scala oraz ReaderWriter2.scala nie kompilują się, gdyż klasy w nich zdefiniowane nie spełniają warunków pozwalających na zdefiniowanie parametrów typu jako kowariantnych i kontrawariantnych.
$ scalac ReaderWriter1.scala ReaderWriter1.scala:1: error: covariant type T occurs in contravariant position in type T of value content_= class ReaderWriter[+T](private var content: T) { ^ ReaderWriter1.scala:3: error: covariant type T occurs in contravariant position in type T of value x def write(x: T) { content = x } ^ two errors found $ scalac ReaderWriter2.scala ReaderWriter2.scala:1: error: contravariant type T occurs in covariant position in type => T of method content class ReaderWriter[-T](private var content: T) { ^ ReaderWriter2.scala:2: error: contravariant type T occurs in covariant position in type => T of method read def read: T = content ^ two errors found
Jakie zatem warunki musi spełniać parametr typu, aby mógł być określony jako kowariantny albo kontrawariantny? Istnieją określone pozycje w definicji typu ogólnego, w których może być użyty typ kowariantny oraz istnieją pozycje, w których może być użyty typ kontrawariantny. Te pierwsze są określane jako pozycje kowariantne, a te drugie jako pozycje kontrawariantne. Jeśli typ kowariantny lub kontrawariantny zostanie użyty w pozycji, w której nie może być użyty, to kompilator powiadomi nas o tym komunikatem błędu. Powyższe przykłady kompilacji plików ReaderWriter1.scala i ReaderWriter2.scala pokazują takie komunikaty. W pierwszym przypadku kompilator protestuje, gdyż nastąpiła próba użycia kowariantnego typu T w pozycji kontrawariantnej, natomiast w drugim dlatego, że nastąpiła próba użycia kontrawariantnego typu T w pozycji kowariantnej.
Specyfikacja języka Scala opisuje zasady dotyczące pozycji kowariantnych i kontrawariantnych w punkcie 4.5. |