Search code examples
scalaexistential-type

Scala existentials placeholder translation for M[_,_] where M[X,Y <: N[X]]


Given the following types

trait N[X]
trait M[X, Y <: N[X]]

How does scala translate this:

M[_,_]

I've tried the following but without success:

scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._

scala> typeOf[Class[_]] =:= typeOf[Class[C] forSome { type C }]
res4: Boolean = true

scala> typeOf[List[Class[_]]] =:= typeOf[List[Class[C] forSome { type C }]]
res5: Boolean = true

scala> typeOf[M[_,_]] =:= typeOf[M[X,Y] forSome { type X; type Y <: N[X] }]
res5: Boolean = false

warning: the existential type M[X,Y] forSome { type X; type Y <: N[X] }, which cannot be expressed by wildcards,  
should be enabled by making the implicit value scala.language.existentials visible.

Quite puzzling? If it cannot be expressed by wildcards then the compiler should produce an error rather than a warning, shouldn't it?


Solution

  • Scala translates M[_,_] into M[X, Y] forSome { type X; type Y }. This is easily proven:

    scala> type Foo = M[_,_]
    defined type alias Foo
    
    scala> type Bar = M[X, Y] forSome { type X; type Y }
    defined type alias Bar
    
    scala> implicitly[ Foo =:= Bar]
    res0: =:=[Foo,Bar] = <function1>
    

    Or using reflection:

    scala> typeOf[Foo] =:= typeOf[Bar]
    res2: Boolean = true
    

    As for the warning you get, all it says is that M[X,Y] forSome { type X; type Y <: N[X] } has no equivalent using wildcards. Wildcards are just syntactic sugar for a limited subset of existential types, and the scala compiler considers existentials an advanced feature that you should enable explicitly, hence the warning (unless the existential can be mapped to simple wildcards, which the compiler does not consider an advanced feature that would mandate to be explicitly enabled, which is why the warning mentions that the existential cannot be expressed by wildcards).