Can an existentially quantified type variable be forced to have only a single type?

前端 未结 2 1830
南方客
南方客 2021-01-13 11:54

Consider the following code

trait Foo[T] {
  def one: Foo[_ >: T]
  def two: T
  def three(x: T)
}

def test[T](f: Foo[T]) = {
  val b = f.one
  b.three(b         


        
相关标签:
2条回答
  • 2021-01-13 12:41

    The problem is the compiler thinks that

    b.two: _>:T
    b.three(_>:T)
    

    i.e. two is a supertype of T and three requires a supertype of T. But a supertype of T is not necessarily assignment compatible with another supertype of T, as in this example:

    A >: B >: C
    def get:A
    def put(B)
    put(get) // type mismatch
    

    So if all the information we have is that they are supertypes of T then we cannot do this safely. We have to explicitly tell the compiler that they are the same supertype of T.

    trait Foo[T] {
      type U <: T
      def one: Foo[U]
      def two: T
      def three(x: T)
    }
    

    Then just set U when you implement the trait:

    val x = new Foo[Dog]{
      type U = Mammal
      ...
    

    I would prefer this approach over the existential types due to the cleaner syntax and the fact that this is core Scala and does not need the feature to be imported.

    0 讨论(0)
  • 2021-01-13 12:56

    def one: Foo[_ >: T] is equivalent to

    def one: Foo[U >: T] forSome {type U >: T}

    this one instead works

    def one: Foo[U forSome {type U >: T}]

    I do not however understand why this would make a difference. It seems like it should not to me. (shrug)

    0 讨论(0)
提交回复
热议问题