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.