Reputation: 13
In the below code excerpt, the last statement does not compile. However, the statement immediately before that one does in fact compile. This second-to-last statement is what I would expect the compiler would convert the last statement to. I do not understand why it does not work. Any help is appreciated.
trait ParameterizedBy[A, B] {
val parameterized: B
}
object ParameterizedBy {
implicit def toParameterized[A, B, C](p: ParameterizedBy[A, B])(
implicit f: B => C): C = f(p.parameterized)
}
trait Wraps[A] {
val wrapped: A
}
object Wraps {
implicit def toWrapped[A](w: Wraps[A]): A = w.wrapped
}
val p = new ParameterizedBy[String, Wraps[Int]] {
override val parameterized: Wraps[Int] = new Wraps[Int] {
override val wrapped = 6
}
}
ParameterizedBy.toParameterized(p)(Wraps.toWrapped) + 5
p + 5
Upvotes: 1
Views: 95
Reputation: 44908
Implicitly converting a method into A => C
is problematic, because the compiler cannot easily enumerate all the possible classes C
that have the expected method +
, and then go and search all the possible methods which take B
and give C
- this search would take forever.
I'd suggest to avoid implicit arguments of type B => C
for unknown type C
. If you want a converter, then give it some specific name, e.g.
trait Unwrap[A, B] extends (A => B)
that you then use only in this chained implicit.
A rough sketch of what you might try instead:
import scala.language.implicitConversions
trait ParameterizedBy[A, B] {
val parameterized: B
}
object ParameterizedBy {
implicit def toParameterized[A, B, C](p: ParameterizedBy[A, B])(
implicit f: Unwrap[B, C]): C = f(p.parameterized)
}
trait Wraps[A] {
val wrapped: A
}
object Wraps {
implicit def toWrapped[A](w: Wraps[A]): A = w.wrapped
}
trait Unwrap[A, B] extends (A => B)
object Unwrap {
implicit def unwrap[A]: Unwrap[Wraps[A], A] = new Unwrap[Wraps[A], A] {
def apply(w: Wraps[A]): A = w.wrapped
}
}
val p = new ParameterizedBy[String, Wraps[Int]] {
override val parameterized: Wraps[Int] = new Wraps[Int] {
override val wrapped = 6
}
}
p - 5 // works
(p: Int) + 5 // works with type ascription (to avoid conflicts with `+ String`)
Upvotes: 1