When using existential types in Scala, it seems the compiler infers each usage of the existential to be a different type parameter, even if they are actually the same.
For a simple contrived example - Given the following code
class Box[T](value:T){
def get:T = value
def contains(check:T):Boolean = value == check
}
I can do the following
val b1 = new Box(1)
b1.contains(b1.get)
However when using existential types...
val b2 : Box[_] = new Box(1)
b2.contains(b2.get)
I get the following error (In scala 2.11.7
[error] /private/tmp/exttest/test.scala:53: type mismatch;
[error] found : (some other)_$6(in value b2)
[error] required: _$6(in value b2)
[error] b2.contains(b2.get)
My assumption would be that the compiler would understand that the same type parameter _$6
is in use in both cases, however it seems to lose track and treat these as seperate types.
Am I fundamentally misunderstanding something about existential types, or is this a bug in the Scala compiler - and if so, is there a best-practice to work around it?
This is probably more of a limitation rather than a bug.
Often easy way to work around this is to move the sensitive code to a generic method:
def containsSelf[T](box: Box[T]): Boolean =
box.contains(box.get)
val b2 : Box[_] = new Box(1)
containsSelf(b2)
Or design your class with type members instead of generics. This may be a bit more boilerplate-y but does exactly what you want:
trait Box {
type Element
def get: Element
def contains(check: Element): Boolean
}
object Box {
type Aux[T] = Box { type Element = T }
def apply[T](value: T): Box.Aux[T] =
new Box {
type Element = T
def get = value
def contains(check: T) = value == check
}
}
val b2: Box = Box(1)
b2.contains(b2.get)
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