Home > Blockchain >  Understanding covariance and lowerbound in Scala
Understanding covariance and lowerbound in Scala

Time:01-16

I struggle to understand Scala's covariance in combination with lower bounds. I will illustrate my confusion in the following code snippet with 2 compilation errors.

class Queue[ T]:
  def enqueue[U >: T](x: U): Queue[U] = null

class IntQueue extends Queue[Int]:
  override def enqueue[Int](x: Int): Queue[Int] =
    println(math.sqrt(x)) // 1) Found: (x : Int) Required: Double
    super.enqueue(x)      // 2) Found: Queue[Any] Required: Queue[Int]

First, there is a generic class Queue which takes one type parameter with covariance annotation . This is OK as I want to make assignments such as val a: Queue[Any] = IntQueue(). Its enqueue method has a lower bound for its type parameter, U >: T. This is needed because the x would otherwise be in a contravariant position, allowing for nasty things, similar to ArrayStoreException in Java's Array. Second, there is a parametrized class IntQueue generated by Queue with specific type being Int.

Questions – why the 1) and 2) compiler errors happen

ad 1)

  • My reasoning is that math.sqrt is defined as def sqrt(x: Double): Double. My argument's type, x, is of type Int. In this case, implicit conversion Int->Long->Float->Double should happen. Why does the compiler doesn't perform implicit conversion?

CodePudding user response:

In your overriding method definition, Int is not what you expect. You're actually defining a type parameter called Int but not referring to the "original" Int type and thus "hiding" the original Int type.

You actually wrote the same as:

override def enqueue[I](x: I): Queue[I] = ...

Declare it as a non overriding method to achieve what you expect:

def enqueue(x: Int): Queue[Int] = ...
  • Related