Search code examples
scalacovariance

Some questions about covariance in Scala


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?


Solution

  • 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.