Some questions about covariance in Scala

  • A+
Category:Languages

I'm trying to understand covariance in Scala, but I cant find any examples that help me with this problem. I' ve got this code:

    class GenericCellImm[+T] (val x: T) {} 

and it compile well, but when I use it

    class GenericCellMut[+T] (var x: T) { } 

it doesn't compile. Why I can't use var (but I can use val) when I'm writing this code? How can I fix it? Also here is similar situation

    abstract class Sequence[+A] {     def append(x: Sequence[A]): Sequence[A]}  

What is the problem?

 


You can't write def append(x: Sequence[A]): Sequence[A]}, as A is in contravariant position in the append argument, while being covariant.

You should write it like this:

abstract class Sequence[+A] {    def append[B >: A](x: Sequence[B]): Sequence[B] } 

You have a great explanation in Why doesn't the example compile, aka how does (co-, contra-, and in-) variance work?

In short:

+A states that it is safe to convert this A to a supertype of A in all context ( A Dog maybe converted to an Animal). If you write append[A](x: Sequence[A]) you are stating that x can only be A or subtypes of A (Dog, yorsay etc), but never a supertype (like Animal), so this contradicts the +A annotation and fails at compilation time. With the signature append[B >: A](x: Sequence[B]) you fix it by avoiding naming A in the function arguments.

So, [B >: A] is defining a lower bound for B, stating that B must be a supertype of A, or A, but never any class below A in the hierarchy, and hence complying with +A signature.

I know covariance and contravariance are complex concepts and hard to understand, I also get confused from time to time.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: