Search code examples
scalatype-inferencetypechecking

Scala type inference and multiple arguments list


(Scala 2.11.8)

Consider the following code:

trait Class[A] {
  def f1[B >: A](arg1: Int)(ord: Ordering[B]): Int

  def f2[B >: A](arg1: Int, ord: Ordering[B]): Int

  def f[B >: A](ord: Ordering[B]): Int = {
    f1(123)(ord) // Compilation error!
    f2(123, ord) // OK
  }
}

Here, line f1(123)(ord) raises type mismatch; found : Ordering[B] required: Ordering[A] Note: B >: A, but trait Ordering is invariant in type T. You may wish to investigate a wildcard type such as _ >: A. (SLS 3.2.10)

If we change the call to f1[B](123)(ord), error disappears.

Why does the presence of multiple arguments list confuses the typechecker? Is this a bug, or an expected result?


Solution

  • It's not a bug - the separation into parameter lists means that the type parameter is inferred based on the first argument list alone:

    f1(123)(ord) 
    

    can be rewritten as:

    val partiallyApplied = f1(123)
    partiallyApplied(ord)
    

    Now - what is partiallyApplied's type? Since the type parameter wasn't explicitly set, and there's no argument / return type to use for inference, the type parametter is inferred to be A (there's no specific B yet! So partiallyApplied's type is (Ordering[A]) => Int), hence using it with Ordering[B] later gives the exception.

    In contrast, when calling:

    f2(123, ord)
    

    Since ord has type Ordering[B], the type parameter can be inferred to be B, hence compilation succeeds.