My scenario is like:
trait A {
type B
def foo(b: B)
}
trait C[D <: A] {
val d: D
def createB(): D#B
def bar() {
d.foo(createB)
}
}
In REPL, it complains
<console>:24: error: type mismatch;
found : D#B
required: C.this.d.B
a.bar(createB())
What's wrong with this ? And (if possible at all) how to correct this code ?
D#B
is a type projection, and is not the same as d.B
. You have a type mismatch because in foo
, B
actually meant this.B
, which as said is not the same as D#B
(the latter being more general).
Informally, you can think of D#B
as representing any possible type that the abstract type B
can take for any instance of D
, while d.B
is the type of B
for the specific instance d
.
See What does the `#` operator mean in Scala? and What is meant by Scala's path-dependent types? for some context.
One way to make it compile it is by changing createB
's return type to d.B
:
def createB(): d.B
However in many cases such a solution is too restrictive because you are tied to the specific instance d
, which might not be what you had in mind.
Another solution is then to replace the abstract type with a type parameter (though it is more verbose):
trait A[B] {
def foo(b: B)
}
trait C[B, D <: A[B]] {
val d: D
def createB(): B
def bar() {
d.foo(createB)
}
}