Contravariance usage in Scala

76 Views Asked by At

As per the definition of contravariance (super class instances will be accepted), my last statement in the below code snippet, should be accepted; but it is thrown with type error. Can you please correct my understanding.

  class A
  class B extends A
  class C extends B
  
  abstract class Box[-T] {
     def set(x : T) :Unit
  }
  
  val x = new Box[B] {
    def set(b:B) = Console println "B"
  }
  
  val y  = new Box[A] {
    def set(a:A) = Console println "A"
  }
  
  val z  = new Box[C] {
    def set(c:C) = Console println "C"
  }  

  x.set(new A)   <-- Type error

But x.set(new C) is fine! So even though "contravariant parameters are accepted as method parameters" is in fact, are covariant parameters actually.

2

There are 2 best solutions below

0
Luis Miguel Mejía Suárez On

You are confusing how contravariance works. x is a Box[B] as such, set accepts values of type B (or any subtype of B because that is what Liskvo says).

However, Box[A] is a subtype of a Box[B]. So you could have passed y where x is expected. Because a Box that can store any A can store a B.
But, a Box that can store only Bs can not store and arbitrary A.

0
Vivick On

It looks like this not how it would work and that's from a conceptual stand point: a B is an A but not the other way around.

As indicated in the scala doc for variances, contravariant type parameters allow to pass a "super-type" instead of the "sub-type", but this applies to what is used within the body (e.g. If the "super-type" already has defined what's used) otherwise I guess it just considers the type and we're back to what I explained before.