Consider path-dependent type
trait Foo[In] {
type Out
def f(v: In): Out
}
implicit val preciseFooInt: Foo[Int] { type Out = String } = new Foo[Int] {
type Out = String
def f(v: Int): String = v.toString
}
where we see output type Out
declared as type member. Also note the precisely declared type of preciseFooInt
instance
Foo[Int] { type Out = String }
Now let's lose the type member precision by forcing assignment to its supertype
val ev: Foo[Int] = preciseFooInt
Because we omitted type refinement { type Out = String }
the compiler does not know the output type is precisely String
which makes sense
scala> val ev: Foo[Int] = preciseFooInt
val ev: Foo[Int] = $anon$1@2fd641f6
scala> val s: String = ev.f(42)
^
error: type mismatch;
found : ev.Out
required: String
However let's do very similar motions but via method parameter declaration
def g(ev: Foo[Int]) = ev.f(42)
Note how method parameter ev
has exactly the same type ascription as variable ev
before, namely Foo[Int]
without the specific type member refinement { type Out = String }
. Nevertheless now there is no loss of type member precision
scala> def g(ev: Foo[Int]) = ev.f(42)
def g(ev: Foo[Int]): ev.Out
scala> val s: String = g(ev = preciseFooInt)
val s: String = 42
What is the difference between the variable declaration and method parameter declaration with respect to type members? Given type ascription was the same in both cases, why was there no loss of information in method parameter case?