In Scala, I've seen the constructs
trait T extends S
and
trait T { this: S =>
used to achieve similar things (namely that the abstract methods in S
must be defined before an instance may be created). What's the difference between them? Why would you use one over the other?
Self type annotations allow you to express cyclic dependencies. For instance:
This is not possible with simple inheritance.
I know this question is old but I would like to add some clarification and examples.
There are three main differences between trait inheritance and self types.
Semantics
Inheritance is one of the relationships with the most coupling of the object paradigm, if A extends B, that means that A is a B.
Let's say we have the following code,
We are saying that a Dog is an Animal. We can send the messages
bark
andstop
togoodboy
because is a Dog, it understand both methods.Now suppose we have a new trait,
This time Security is NOT an Animal, and that is fine because would be semantically incorrect if we affirm that a Security is an Animal, they are different concepts, that can be used together.
So now we can create a new kind of dog,
guardDog
is a Dog, an Animal and Security. It understandstop
,bark
andlookout
because is a Dog with Security.But what happens if we create a new dog like this?
guardDog2
is just a Dog, so we can't calllookout
method. (okok, it's a Dog with Security, but we just see a Dog)Cyclic Dependencies
Self Types allow us to create cyclic dependencies between types.
The following code doesn't compile.
This kind of code is very common in dependency injection (cake pattern).
Versatility
Last but not least, who uses our traits can decide the order in which they are used, so thanks to Trait Linearization the final result can be different although the traits used are the same.
With normal inheritance we can't do that, the relations between traits and classes are fixed.
Hope this can be useful.
Although it doesn't answer your question, I was trying to understand the self-type annotations and basically got lost in answers, and somehow ended up cycling through variations of your question, which focuses on usage of self-type annotations for stating dependencies.
So here I post a description of an use case where self-type annotations are well illustrated, namely something like a type-safe case of 'this' as a subtype:
http://programming-scala.labs.oreilly.com/ch13.html#SelfTypeAnnotationsAndAbstractTypeMembers
hoping that it would be helpful to those who end up on this question by chance (and, like me, didn't have time to read a scala book before starting to explore :-) )
Since asking the question I came across these posts:
Spiros Tzavellas talks about using a trait as the public interface and the self type as a helper that must be mixed in by the implementation class.
For example:
A Tour of Scala discusses using self type annotations with abstract type members - presumably it's not possible to
extend
an abstract type member(?)I'd use self-types for dependency-management: This trait requires another trait to be mixed in. And I'd use inheritance to refine another trait or interface.
Just as an example:
Now, if FooRemoting and FooPersistence both would have inherited from FooService, and FooService has members and methods, how would Services look like?
Whereas for inheritance, we'd have something like:
The answer is "circularity". But not only.
Self type annotation solves for me the fundamental problem of inheritance: what you inherit from cannot use what you are. With the self type, everything becomes easy.
My pattern is the following and can be considered as a degenerated cake:
You can explode your class in multiple behaviours which can be called from anywhere in the assembly, while staying cleanly typed. No need for the painful indirection too often (and wrongly) identified with the cake pattern.
Half (if not the totality) of the convoluted Java DI frameworks of the last ten years have been devoted to do this, of course without the typing. People still using JAVA in this domain are clearly loosing their time: "SCALA ouakbar".