Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Existential types for F-Bounded Polymorphic types and non-generic subtypes?

I have two subtypes that I need to be F-bounded polymorphic by a type A, and a subtype of one of those subtypes, i.e.

trait A[T <: A[T]] {
  def x: T
}
trait Ter extends A[Ter]
trait For extends A[For]
trait C extends Ter

Next I try to implement a concrete type

case class F2(l: List[A[_]]) extends For {
  def x: For = F2(l.map(_.x))
}

But this fails to compile with:

<console>:11: error: type mismatch;
 found   : List[Any]
 required: List[A[_]]
         def x: For = F2(l.map(_.x))
                              ^

So, google says I need to use existential types, which makes sense, so I try:

import scala.language.existentials

type SomeA = T forSome { type T <: A[T] }

case class F1(l: List[SomeA]) extends For {
  def x: For = F1(l.map(_.x))
}

But, now I face a new problem when I try to instantiate

trait Example {
  val b: Ter
  val c: C
  val d: For

  // Works fine
  val l1: List[A[_]] = List(b, c, d)
  // But this doesn't work, fails to compile (see below)
  val l2: List[SomeA] = List(b, c, d)

  val f1 = F1(l2)
}

The compile error:

<console>:22: error: type mismatch;
 found   : C
 required: SomeA
    (which expands to)  T forSome { type T <: A[T] }
         val l2: List[SomeA] = List(b, c, d)
                                       ^

Why do I get this error? Surely C is a subtype of Ter, which in turn is a subtype of A[Ter], therefore C is a subtype of A[Ter], therefore there exists a T namely Ter such that C is a subtype of A[T], therefore C is a subtype of SomeA.

It's as if the transitivity of subtyping isn't working. When I hack it with c.asInstanceOf[SomeA] my code compiles and my unit tests pass. Could it be a compiler bug?

I also thought that List[A[_]] was stronger typing than List[SomeA], i.e. the former was saying the list consists of A[T] some fixed type T, where the latter is saying the list consists of A[T] where T is not fixed.

BOUNS If you can explain why the currently accepted answer works, i.e. why the compiler cannot work out that the type is valid without the ascription.

like image 802
samthebest Avatar asked Nov 10 '22 18:11

samthebest


1 Answers

I guess the compiler needs some help. The following should work:

val l2 = List[SomeA](b, c: Ter, d)
like image 182
Andreas Flueckiger Avatar answered Nov 15 '22 11:11

Andreas Flueckiger