Why in Covariant class in Scala var in constructor is forbidden?

270 Views Asked by At

I have class

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

When I try to compile it I get:

Error:(6, 33) covariant type T occurs in contravariant position in type T of value x_=
  class GenericCellImm[+T] (var x: T) {

How to fix it? What is the problem reason?

1

There are 1 best solutions below

0
SergGr On

Covariant generic type means that if you have classes Base and Child that extends Base, then in every context where GenericClass[Base] is a correct type using an object of type GenericClass[Child] will also be correct. As a rough approximation it means that if your GenericClass[T] provides read-only API, you may make +T covariant because it is always safe to return Child instead of Base. However this is not true if you have some writeable API in your GenericClass[T]. Consider following code:

def writeDefault(gc: GenericClass[Base]):Unit = {
   gc.x = new Base()
}

This code is safe if gc is really of type GenericClass[Base] but if you let GenericClass[Child] there, you'll write a value of type Base to a field that is typed with Child and this breaks expected type safety. Consider

class Base(){}
class Child(childField:Int) extends Base {}

def bad():Unit = {
   val gc = new GenericClass[new Child(1)]
   writeDefault(gc)
   println(gc.childField) // Oops! there is no childField in Base
}

And this is exactly why the compiler doesn't allow your code with covariance.

If you want get some real suggestion on how to fix it, you should describe the higher-level problem you are trying to solve. Without such a description it is really hard to guess whether just using val instead of var is what you need or whether you just need to remove covariance altogether or if you need a more complicated code.