Reputation: 35
I want to extend my parameterized trait Field[T]
with method returning this.type
using Pimp my Library pattern. But I stuck with compiler errors. I tried some variants, but without success.
Am I doing it wrong? Or asking for the impossible?
Here is my test example:
trait Field[T]
class IntField extends Field[Int] {
def getInt = 5
}
// Variant 1: return field.type
object Var1 {
implicit class RichField[T](val field: Field[T]) {
def bar(fn: T => String): field.type = {
// some actions using T
field
}
}
new IntField().bar(_.toString).getInt // Error: value getInt is not a member of Field[Int]
}
// Variant 2: use two type parameters
object Var2 {
implicit class RichField[T, F <: Field[T]](val field: F) {
def bar(fn: T => String): F = {
// some actions using T
field
}
}
new IntField().bar(_.toString).getInt // <-- Error: value bar is not a member of IntField
}
// Variant 3: use higher kinds
object Var3 {
import scala.language.higherKinds
implicit class RichField[F[X] <: Field[X], T](val field: F[T]) {
def bar(fn: T => String): F[T] = {
// some actions using T
field
}
}
new IntField().bar(_.toString).getInt // <-- Error: value getInt is not a member of Field[Int]
}
Update: Parameter T
is important for method bar
, it cannot be ignored.
Upvotes: 1
Views: 248
Reputation: 32719
In variant 2, you are not using T
anywhere. Just remove it and the compiler won't be confused anymore:
implicit class RichField[F <: Field[_]](val field: F) {
def bar: F = field
}
UPDATE: If you actually need T
, as you mentioned in a comment, a possible workaround is this:
implicit class RichField[T, F <: Field[_]](val field: F with Field[T]) {
def bar(fn: T => String): F = {
// some actions using T
field
}
}
And here's a proof that it works as expected (using toString
as in your example is not a good test given that toString
is available on every class, so even if the compiler inferred Any
the code would have compiled):
scala> case class Foo(name: String)
defined class Foo
scala> class FooField extends Field[Foo] {
| def getInt = 5
| }
defined class FooField
scala> new FooField().bar(_.name).getInt
res8: Int = 5
Upvotes: 2