There are two ways to define a class with type parameters:
trait A { type T ; def foo(i:T) = print(i) }
class B extends A { type T = Int }
or
trait A[T] { def foo(i:T) = print(i) }
class B extends A[Int] {}
What's the difference and are they exactly same for scala compiler? Which way is better (in which cases)?
CodePudding user response:
The former isn't [just] a type alias, it's a path dependent type. Meaning the type of T
in enclosed in an instance of A
.
With a path dependent type, it's not possible to know the type of T
given an instance of A
(only if you know the subtype). Consider
val a: A = ???
a.foo(???)
With the generic type, we do (typically) know the type of T
without knowing the subtype of A
. Consider
val a: A[Int] = ???
a.foo(5)
On the other hand, with path dependent types you can do
trait A { type T; def foo(s:String): T }
class B extends A { type T = Int; def foo(s: String) = s.length }
def fun(a: A): A#T = a.foo("hello")
val out: Int = fun(new B()) // 5
We can have the output type of fun
depend on the parameter being passed, but not need to add a generic parameter.