scala> class A
defined class A
scala> class B {this: A => }
defined class B
scala> new B
<console>:10: error: class B cannot be instantiated because it does not conform
to its self-type B with A
new B
^
Class B sets the self type to class A, therefore class B (or a subclass of it) has to extend class A to create an instance of B. But is this possible at all, since a subclass of B can only extend one class (and this is class B) ?
So this leads me to the question, does it make sense to declare the self type of a class to another class in any case ?
You are right with the observation that this definition can not lead to a concrete implementation, as you cannot mix two classes, only traits. So the short answer is ‘no’, either should be a trait.
There are several questions on Stackoverflow regarding self-types. Two useful ones are these:
In the second question, there is a good answer by Ben Lings who cites the following passage from the blog of Spiros Tzavellas:
For example, if
A(assume it’s a trait and not a class now!) is a logger. You don’t want to expose forBpublicly the logging API mixed in byA. Therefore you would use a self-type and not mixin. Within the implementation ofByou can call into the logging API, but from the outside it is not visible.On the other hand, you could use composition in the following form:
The difference now is that
Bmust refer tologgerwhen wanting to use its functionalityBhave access to theloggerBandAdo not compete in namespace (e.g. could have methods of the same name without collision)I would say that self-types are a fairly peripheral feature of Scala, you don’t need them in many cases, and you have options like this to achieve almost the same without self-types.