views:

985

answers:

5

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:

trait B
trait A { this: B => }

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:

trait B
trait A extends B

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?

+2  A: 

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.

IttayD
+1  A: 

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.

kikibobo
+3  A: 

Self types allow you to define cyclical dependencies. For example you can achieve this:

trait A {self: B=>}
trait B {self: A=>}

Inheritance using extends does not allow that. Try:

trait A extends B
trait B extends A
error:  illegal cyclic reference involving trait A

In the Odersky book, look at section 33.5 (Creating spreadsheet UI chapter) where it mentions:

In the spreadsheet example, class Model inherits from Evaluator and thus gains access to its evaluation method. To go the other way, class Evaluator defines its self type to be Model, like this:

package org.stairwaybook.scells
trait Evaluator { this: Model => ...

Hope this helps.

Mushtaq Ahmed
I hadn't considered this scenario. Its the first example of something that I've seen that isn't the same as a self-type as it is with a subclass. However, it seems kind of edge-casey and, more important, it seems like a bad idea (I usually go far out of my way NOT to define cyclic dependencies!). Do you find this to be the most important distinction?
Dave
I think so. I do not see any other reason why I would prefer self-types to extends clause. Self-types are verbose, they do not get inherited (so you have to add self-types to all subtypes as a ritual) and you can only see member but can't override them.I am well aware of Cake pattern and many posts mentioning self-types for DI. But somehow I am not convinced. I had created a sample app here long back (http://bitbucket.org/mushtaq/scala-di/). Look specifically at /src/configs folder. I achieved DI to replace complex Spring configurations without self-types.
Mushtaq Ahmed
Mushtaq, we're in agreement. I think Daniel's statement about not exposing unintentional functionality is an important one but, as you put it, there is a mirror view of this 'feature'... that you cannot override the functionality or use it in future subclasses. This pretty clearly tells me when design will call for one over the other. I'll be avoiding self-types until I find a genuine need -- ie if I start using objects as modules as Daniel points out. I'm autowiring dependencies with implicit parameters and a straightforward bootstrapper object. I like the simplicity.
Dave
+10  A: 

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 B extends A, then B is an A. When you do dependency injection, you want B to require A, not to be an A. For example:

scala> trait User { def name: String }
defined trait User

scala> trait Tweeter {
     |   user: User =>
     |   def tweet(msg: String) = println(name+": "+msg)
     | }
defined trait Tweeter

scala> trait Wrong extends Tweeter {
     |   def noCanDo = name
     | }
<console>:8: error: illegal inheritance;
 self-type Wrong does not conform to Tweeter's selftype Tweeter with User
       trait Wrong extends Tweeter {
                           ^
$iw.$iw.Wrong <: $iw.$iw.Tweeter with $iw.$iw.User?
  $iw.$iw.Wrong <: $iw.$iw.Tweeter?
  true
  $iw.$iw.Wrong <: $iw.$iw.User?
    <notype> <: $iw.$iw.User?
    false
  false
false
<console>:9: error: not found: value name
         def noCanDo = name
                       ^

Which would cause no error if subclassing was used.

Daniel
I guess you are referring to this article by Jonas Boner: (http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html)
Mushtaq Ahmed
Thanks. The Cake pattern is 90% of what I mean why I talk about the hype around self-types... it is where I first saw the topic. Jonas Boner's example is great because it underscores the point of my question. If you changed the self-types in his heater example to be subtraits then what would be the difference (other than the error you get when defining the ComponentRegistry if you don't mix in the right stuff?
Dave
That's the one, Mushtaq. Thanks.
Daniel
@Dave: You mean like `trait WarmerComponentImpl extends SensorDeviceComponent with OnOffDeviceComponent`? That would cause `WarmerComponentImpl` to have those interfaces. They would be available to anything that extended `WarmerComponentImpl`, which is clearly wrong, as it is _not_ a `SensorDeviceComponent`, nor a `OnOffDeviceComponent`. As a self type, these dependencies are available _exclusively_ to `WarmerComponentImpl`.A `List` could be used as an `Array`, and vice versa. But they just aren't the same thing.
Daniel
Thanks Daniel. This is probably the major distinction I was looking for. The practical problem is that using subclassing will leak functionality into your interface that you don't intend. Its a result of the violation of the more theoretical "is-part-of-a" rule for traits. Self-types express a "uses-a" relationship between parts.
Dave
@Dave: Yes. It's perhaps interesting to note that traits and self-types are, perhaps, most important when using object as modules. Or, at least, that's how I see it. Not necessarily an `object`, either, which is a singleton.
Daniel
+3  A: 

One additional difference is that self-types can specify non-class types. For instance

trait Foo{ this => {def close:Unit} }

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.

Dave Griffith