I am researching about existential types in Scala 2.12.x
. For that I'm testing the following code:
trait Parent
class ChildA extends Parent
class ChildB extends Parent
def whatIsInside(opt: Option[_ <: Parent]): String = {
opt match {
case _: Option[_ <: ChildA] => "ChildA"
case _: Option[_ <: ChildB] => "ChildB"
case _ => throw new IllegalArgumentException("unknown type")
}
}
whatIsInside(Some(new ChildA))
I don't expect this to work at runtime because of type erasure, but nevertheless this does not even compile. I am getting the following error:
[error] ExistentialTypes.scala:12:24: not found: type _$2
[error] case _: Option[_ <: ChildA] => "ChildA"
[error] ^
[error] ExistentialTypes.scala:13:24: not found: type _$3
[error] case _: Option[_ <: ChildB] => "ChildB"
[error] ^
Can someone explain these errors?
(Not a full answer, but a few notes and links; Maybe it can serve as a starting point for someone else)
In 2.12.13, the compiler seems to be able to prove that F[_ <: X]
and F[X]
are the same type if X
occurs in covariant position:
println(implicitly[Option[_ <: ChildA] =:= Option[ChildA]])
This compiles (with warnings, but it compiles):
trait Parent
class ChildA extends Parent
class ChildB extends Parent
def whatIsInside(opt: Option[_ <: Parent]): String = {
opt match {
case _: Option[ChildA] => "ChildA"
case _: Option[ChildB] => "ChildB"
case None => "None"
case _ => throw new Error("meh")
}
}
This does not compile:
trait Parent
class ChildA extends Parent
class ChildB extends Parent
def whatIsInside(opt: Option[_ <: Parent]): String = {
opt match {
case _: Option[_ <: ChildA] => "ChildA"
case _: Option[_ <: ChildB] => "ChildB"
case None => "None"
case _ => throw new Error("meh")
}
}
So, it seems that it must have something to do with the bounds inference for the synthetic _$2
type-variable.
Also, this compiles:
def testConforms[A >: Nothing <: ChildA](ca: Option[A]): Option[_ <: Parent] = ca
so, unless I'm misinterpreting the spec:
If there exists a substitution
σ
over the type variablesa_i,…,a_n
such thatσT
conforms topt
, one determines the weakest subtype constraintsC1
over the type variablesa1,…,an
such thatC0 ∧ C1
implies thatT
conforms to [the expected type]pt
.
, the pt
would be Option[_ <: Parent]
, then a1,...,an
would be the single synthetic type _$2
, and the constraints _$2 >: Nothing <: ChildA
should make the type Option[_$2]
conform to Option[_ <: Parent]
. So, it seems that it should work, but doesn't.
Bonus
If you just wanted to make it work, then just skip all those wildcards, they aren't needed:
trait Parent
class ChildA extends Parent
class ChildB extends Parent
def whatIsInside(opt: Option[Parent]): String = {
opt match {
case Some(_: ChildA) => "ChildA"
case Some(_: ChildB) => "ChildB"
case None => "None"
case _ => throw new Error("meh")
}
}
whatIsInside(Some(new ChildA))
whatIsInside(Some(new ChildB))
whatIsInside(None)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With