With the following class hierarchy:
trait Provider[A] {
def get(): Seq[A]
}
abstract class ProviderImpl[A] extends Provider[A] {
final override def get(): Seq[A] = Seq()
}
trait HasX {
def getX: Int
}
trait RefinedProvider[A <: HasX] extends Provider[A]
class TypedProviderImpl extends ProviderImpl[HasX] with RefinedProvider[HasX]
I want to be able to do this:
val provider: RefinedProvider[_] = new TypedProviderImpl()
provider.get() map (_.getX)
But it doesn't work, because the return type of provider.get()
is Seq[Any]
which seems wrong to me because it's a RefinedProvider
, so get()
should return a Seq[_ <: HasX]
.
Question: I can fix the problem with an existential type, but why can't the compiler enforce this for me?
val provider: RefinedProvider[T] forSome { type T <: HasX } = ...
Ticket SI-2385 suggests this is simply part of the spec to interpret A[_]
as A[T] forSome
{ type T >: Nothing <: Any }
and not infer tighter bounds if possible. One could wonder whether the spec shouldn't be updated then.
Ticket SI-6169 seems to suggest that some things would stop working if tighter bounds were inferred. I'm not sure how and why though.
A small compromise is that you can shorten
val provider: RefinedProvider[T] forSome { type T <: HasX }
to
val provider: RefinedProvider[_ <: HasX]