Why does scala require existential types to restrict a generic bound?

我们两清 提交于 2020-06-18 15:56:48

问题


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 } = ...

回答1:


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]



回答2:


This is caused by you are using wildcard: _ to state your variable type: val provider: RefinedProvider[_], _ it means Any type, you can do it like:

val provider = new TypedProviderImpl() // the compiler and IDE will auto infer **provider** type

or

val provider: RefinedProvider[HasX] = new TypedProviderImpl() // explicitly provider type


来源:https://stackoverflow.com/questions/42696319/why-does-scala-require-existential-types-to-restrict-a-generic-bound

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!