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?
Best Answer
It is predominately used for Dependency Injection, such as in the Cake Pattern. There exists a great article covering many different forms of dependency injection in Scala, including the Cake Pattern. If you Google "Cake Pattern and Scala", you'll get many links, including presentations and videos. For now, here is a link to another question.
Now, as to what is the difference between a self type and extending a trait, that is simple. If you say
B extends A
, thenB
is anA
. When you use self-types,B
requires anA
. There are two specific requirements that are created with self-types:B
is extended, then you're required to mix-in anA
.A
.Consider the following examples:
If
Tweeter
was a subclass ofUser
, there would be no error. In the code above, we required aUser
wheneverTweeter
is used, however aUser
wasn't provided toWrong
, so we got an error. Now, with the code above still in scope, consider:With
Right
, the requirement to mix-in aUser
is satisfied. However, the second requirement mentioned above is not satisfied: the burden of implementingUser
still remains for classes/traits which extendRight
.With
RightAgain
both requirements are satisfied. AUser
and an implementation ofUser
are provided.For more practical use cases, please see the links at the start of this answer! But, hopefully now you get it.