Here is a simple reproducer, where I define a "commutative" pair type that comes with an implicit reordering conversion. The implicit conversion is applied by the compiler as expected if the argument to function f
is in a pre-existing named value (t
in the example). However, if I try to call f
directly on literal CommutativePair
, it fails with a type error. The compiler is not applying the implicit reordering conversion in that case.
object repro {
import scala.language.implicitConversions
case class CommutativePair[A, B](a: A, b: B)
object CommutativePair {
// Support a kind of commutative behavior via an implicit reordering
implicit def reorderPair[B, A](pair: CommutativePair[B, A]) =
CommutativePair(pair.b, pair.a)
}
// The idea is to allow a call to 'f' with Pair[Int, String] as well,
// via implicit reorder.
def f(p: CommutativePair[String, Int]) = p.toString
val t = CommutativePair(3, "c")
// This works: the implicit reordering is applied
val r1 = f(t)
// This fails to compile: the implicit reordering is ignored by the compiler
val r2 = f(CommutativePair(3, "c"))
}
I believe it is hitting the limit of scala inference, triggered by the order in which it searches for solutions. In the first situation:
val t = CommutativePair(3, "c")
The inference has locked the type to CommutativePair[Int,String]
, because it is the only one that could work based on the parameters. So when it calls:
val r1 = f(t)
It gets a type mismatch on Commutative[Int,String]
=!= Commutative[String,Int]
, then it searches for implicits and finds the one above.
In the second case, scala is trying to figure out the types, working its way in from the outside:
val r2 = f(CommutativePair(3, "c"))
f
, must take Commutative[String,Int]
.CommutativePair(...,...)
must be Commutative[String,Int]
(since, it hasn't figured out it's type from the it's parameters, yet).CommutativePair(...)
and finds them to be the wrong type. But this won't trigger the implicit conversion because it thinks the mismatch is in the parameters, not on the whole CommutativePair(...)
.Indeed, locking down type params (by passing them explicitly or by binding to a val first) fixes the error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With