Jay Taylor's notes
back to listing indexfunctional programming - What is the difference between scala self-types and trait subclasses? - Stack Overflow
[web search]
Self-types seem to be important so I want to know why they are useful. From what I can gather, a self-type for a trait A:
says that "A cannot be mixed into a concrete class that does not also extend B". (sidenote: I'm also seeing this fail in the REPL when mixed into an abstract class that does not extend B, which the book "Programming in Scala" says should work, but I'm using a Scala 2.8 daily build.) But if I say:
then this means that "any (concrete or abstract) class mixing in A will also be mixing in B". But 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. I have considered that the difference may be the order of function overloading when using a self-type instead of an extends clause... but this seems like a minor distinction, not worthy of the hoopla over self-types. What am I missing? | |||||||||
| |||||||||
It is used for Dependency Injection, such as in the Cake Pattern. I once read a great article covering many different forms of dependency injection in Scala, including the Cake Pattern, but I can't find it right now (edit: thanks to Mushtaq, it is now linked). If you look up google for Cake Pattern and Scala, you'll get many links, including presentations and videos. For now, there's a publicly-available chapter of O'Reilly's Programming Scala book with a section on it. Now, as to what is the difference between a self type and extending a trait, that is simple. If you say
Which would cause no error if subclassing were used.
| |||||||||||||||||||||||||||||||||
|
in the first case, a sub-trait or sub-class of B can be mixed in to whatever uses A. So B can be an abstract trait. | |||
add comment |
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 the Closeable interface. | |||||||||
|
Self types allow you to define cyclical dependencies. For example you can achieve this:
Inheritance using extends does not allow that. Try:
In the Odersky book, look at section 33.5 (Creating spreadsheet UI chapter) where it mentions:
Hope this helps. | |||||||||||||||||||||||||||||||||
|
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.
| |||||||||
|
Check the following article it containes very simple but real word examples that made me understand basic of self-types in a minute. | |||
add comment |
Scala self-types are not very flexible because you cannot have:
as
Yes, admittedly you can have mutually-recursive dependencies with self-types - but how often do you need something like that? | |||
add comment |