scalagenericscovariancetype-bounds

Understanding covariance and lowerbound in Scala


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)


Solution

  • 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] = ...