Home > database >  Covariance and mutable attribute
Covariance and mutable attribute

Time:08-01

Why I can't assign to the mutable attribute?

class X[ T](t: T) {
  var _t: T = t   // Error. Ok if this is val.
}

The error is:

covariant type T occurs in a contravariant position in type T of value _t_=
  var _t: T = t

I try to think about this.

  • Suppose B <: A, which means class B is a subclass of class A.
  • Then, X[B] <: X[A].
  • I can assign an object xb of class X[B] to an instance xa of class X[A].
  • Then we assign xb._t (type B) to var _t: A in xa.
  • This seems to be fine.

What is wrong here?

CodePudding user response:

Your assumption is correct. Not only you can assign something of type A, but you could also assign something of type A which would not be of type B. So you would end up violating the type soundness at runtime.

Here's a more easy-to-follow example. Suppose you have the nonvariant Cell type:

  class Cell[T](elem: T) {
    var curr: T = elem
  }

Now assume for a moment that this type was declared covariant instead, as in Cell[ T] - and that this code would pass the Scala compiler type check (it doesn't). Then you could write the following problematic code:

val c1 = new Cell[String]("abc")
val c2: Cell[Any] = c1
c2.curr = 1
val s: String = c1.curr        // violates the type soundness at runtime

If Cell would be covariant, taken individually, each line of code would compile just fine. But taken together as a whole, these lines end up assigning an Int to a String. This would clearly throw a ClassCastException at runtime.

So even though the faulty line is the last one, actually it is the second line the one to blame, because the other ones are just too simple and too fundamental. In natural language, this would translate as follows:

A Cell of String is not also a Cell of Any because there are things you can do with a Cell of Any that you cannot do with a Cell of String. For example, you cannot assign an Int to the curr field of a Cell of String.

This is why, if you would make Cell covariant, your code would fail to with the same error:

error: covariant type T occurs in contravariant position in type T of value curr_=
    var curr: T = elem
  • Related