Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala existentials - type mismatch, unable to infer T =:= T

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?

like image 619
James Davies Avatar asked Feb 07 '23 21:02

James Davies


1 Answers

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)
like image 196
ghik Avatar answered Feb 16 '23 04:02

ghik