Reputation: 325
I have implicit classes with nested type parameters to provide relevant methods to the data-object only when certain conditions are met and to store type information for later use. Somehow a nested type parameter only works with a wildcard but not with a type parameter. I do not understand why... The following piece of code works:
trait A
trait AB extends A
trait AC extends A
trait ByA[T, AX <: A]
case class ByAX[T, AX <: A]() extends ByA[T, AX]
case class Wrapper[T]()
implicit class WithByAB[T](tpe: Wrapper[_ <: ByA[T, AB]]) {
def printsomething(): Unit = {
println("WithByAB")
}
}
Wrapper[ByAX[String, AB]]().printsomething()
//Wrapper[ByAX[String, AC]]().printsomething() does not compile (expected)
This one does not:
trait A
trait AB extends A
trait AC extends A
trait ByA[T, AX <: A]
case class ByAX[T, AX <: A]() extends ByA[T, AX]
case class Wrapper[T]()
implicit class WithByAB[T, S <: ByA[T, AB]](tpe: Wrapper[S]) {
def printsomething(): Unit = {
println("WithByAB")
}
}
Wrapper[ByAX[String, AB]]().printsomething()
//Wrapper[ByAX[String, AC]]().printsomething() does not compile (expected)
It looks like the compiler cannot resolve type T but if the first example works and preserves the parameter-type information, why not in the second example?!
Upvotes: 1
Views: 499
Reputation: 149518
The problem is that the scala compiler isn't able to deduce that ByAX[String, AB]
actually conforms to WithByAB[T, S <: ByA[T, AB]]
. It is unable to deduce that T
conforms to String
only from binding S
.
We can see that when compiling with -Xlog-implicits
:
λ scalac -Xlog-implicits Implicit.scala
Implicit.scala:22: WithByAB is not a valid implicit value for Wrapper[ByAX[String,AB]] => ?{def printsomething: ?} because:
inferred type arguments [Nothing,ByAX[String,AB]] do not conform to method WithByAB's type parameter bounds [T,S <: ByA[T,AB]]
Wrapper[ByAX[String, AB]]().printsomething()
^
Implicit.scala:22: error: value printsomething is not a member of Wrapper[ByAX[String,AB]]
Wrapper[ByAX[String, AB]]().printsomething()
^
one error found
Note how the compiler is unable to extract String
from ByAX
first type parameter. This is because from the compilers point of view, it has S
which is bound by ByAX
, but it is unaware of it's higher order or it's internal binding to String
, all it can infer is a single type, merely S
.
We can work around this by making Wrapper
a bit more verbose
case class Wrapper[T, S]()
implicit class WithByAB[T, S <: ByA[T, AB]](tpe: Wrapper[T, S]) {
def printsomething(): Unit = {
println("WithByAB")
}
}
Wrapper[String, ByAX[String, AB]]().printsomething()
Or, as you've noted, by making Wrapper
bind to an existential.
Upvotes: 2