Assume the existence of the following types and method:
trait X[A <: X[A]]
case class C extends X[C]
def m(x: PartialFunction[X[_], Boolean])
I want to be able to create a PartialFunction to be passed into m
.
A first attempt would be to write
val f: PartialFunction[X[_], Boolean] = {
case c: C => true
}
m(f)
This fails with type arguments [_$1] do not conform to trait X's type parameter bounds [A <: X[A]]
. So, it seems we have to constraint X
's type parameters.
A second attempt:
val f: PartialFunction[{type A <: X[A]}, Boolean] = {
case c: C => true
}
m(f)
This fails on the application of m
because PartialFunction[AnyRef{type A <: X[this.A]},Boolean] <: PartialFunction[X[_],Boolean]
is false.
Is there any way not involving casting that actually satisfies the compiler both on the definition of the partial function and on the application of m
?
I'm not sure what exactly you want, but since you are using an existential type (in disguise of the _
syntax), this is how you can make that work:
val f: PartialFunction[X[A] forSome {type A <: X[A]}, Boolean] = {
case c : C => true
}
The _
syntax isn't good enough here, since you need to give the existential type the right upper bound. That is only possible with the more explicit forSome
syntax.
What I find surprising, though, is that Scala accepts the declaration
def m(x: PartialFunction[X[_], Boolean])
in the first place. It seems weird that it even considers X[_]
a well-formed type. This is short for X[A] forSome {type A <: Any}
, which should not be a valid application of X
, because it does not conform to the parameter bounds.