Consider this:
object TypeProblem {
trait A {
type T
val set = Set[T]()
}
trait B {
def b()
}
trait FooBad { this: A =>
type T <: B
def x {
set.foreach(_.b())
}
}
trait FooOk { this: A =>
type MyT <: B
type T = MyT
def x {
set.foreach(_.b())
}
}
}
The compiler complains that value b is not a member of FooBad.this.T So why does FooOk work where I define a new type MyT and assigning T to MyT?
The self type of FooBad is expanded by the compiler to FooBad with A (so that you can still access the members you define yourself). That means that T gets the definition in A, and not the one in FooBad, as you'd expect. You can fix your code by changing the definition of FooBad to explicitly add your own type:
trait FooBad { this: A with FooBad =>
..
}
or even better by using subclassing
trait FooBad extends A {
..
}
It is my belief that in most cases self-types should be replaced by plain subclassing. It is simpler to understand, less scary, and leads to better encapsulation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With