A self-type for a trait A
:
trait B
trait A { this: B => }
says that "A
cannot be mixed into a concrete class that does not also extend B
".
On the other hand, the following:
trait B
trait A extends B
says that "any (concrete or abstract) class mixing in A
will also be mixing in B".
Don't these two statements mean the same thing? The self-type seems to serve only to create the possibility of a simple compile-time error.
What am I missing?
A self type lets you specify what types are allowed to mixin a trait. For example, if you have a trait with a self type
Closeable
, then that trait knows that the only things that are allowed to mix it in, must implement theCloseable
interface.Update: A principal difference is that self-types can depend on multiple classes (I admit that's a bit corner case). For example, you can have
This allows to add the
Employee
mixin just to anything that is a subclass ofPerson
andExpense
. Of course, this is only meaningful ifExpense
extendsPerson
or vice versa. The point is that using self-typesEmployee
can be independent of the hierarchy of the classes it depends on. It doesn't care of what extends what - If you switch the hierarchy ofExpense
vsPerson
, you don't have to modifyEmployee
.Section 2.3 "Selftype Annotations" of Martin Odersky's original Scala paper Scalable Component Abstractions actually explains the purpose of selftype beyond mixin composition very well: provide an alternative way of associating a class with an abstract type.
The example given in the paper was like the following, and it doesn't seem to have an elegant subclass correspondent:
One additional difference is that self-types can specify non-class types. For instance
The self type here is a structural type. The effect is to say that anything that mixes in Foo must implement a no-arg "close" method returning unit. This allows for safe mixins for duck-typing.