The code:
object Test {
import scala.language.implicitConversions
case class C1() {}
case class C2() {}
implicit def c1ToC2(in: C1): C2 = C2()
def from[A, B](in: A)(implicit f: A => B): B = f(in)
def fails(): Future[C2] = {
val future: Future[C1] = Future.successful(C1())
future.map(from) // this line fails to compile!
}
def compiles1(): Future[C2] = {
val future: Future[C1] = Future.successful(C1())
future.map(x => from(x))
}
def compiles2(): Future[C2] = {
val future: Future[C1] = Future.successful(C1())
future.map(from[C1, C2])
}
}
In this example, only the fails
method fails to compile. The error message is:
Error:(23, 16) No implicit view available from A => B. future.map(from)
I'm confused about why no implicit view is found. Based on the compiles1
and compiles2
methods, which both successfully compile, it seems there is an implicit view available from A => B.
What is going on here, and why do the two compilesN
methods work, but fails
does not?
My background: I'm still learning Scala, so it could easily be the case that I'm missing something pretty obvious. :)
I'm on Scala 2.11.8.
The compiler attempts to resolve implicits before eta-expansion of from
into a function, so the type parameters of from
are not yet inferred when you call it like this:
future.map(from)
compiles2
obviously works because you supply the type parameters on your own. When you call future.map(from[C1, C2])
, the compiler knows it will need an implicit C1 => C2
, because that's what you've told it.
With compiles1
, the difference is a little more subtle, but it stems from the fact that future.map(from)
and future.map(x => from(x))
are actually very different things. The former uses eta-expansion, which fails for the aforementioned reasons. With future.map(x => from(x))
, there is no eta-expansion happening. Instead, you have an anonymous function that simply calls from
instead of eta-expanding it. Therefore, the compiler can infer the type of x
, which tells us that x
is a C1
(in this case), and it can find the implicit conversion c1ToC2
that satisfies the type parameters of from
while resolving the implicit and the final return type of the method, Future[C2]
.