396

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?

Jacek Laskowski
  • 64,943
  • 20
  • 207
  • 364
Dave
  • 7,229
  • 12
  • 33
  • 42
  • I'm actually interested here in the differences between self types and subclassing in traits. I do know some of the common uses for self-types; I just can't find a reason why they wouldn't be more clearly done the same way with subtyping. – Dave Jan 03 '10 at 02:33
  • 33
    One can use type parameters within self-types: `trait A[Self] {this: Self => }` is legal, `trait A[Self] extends Self` isn't. – Blaisorblade Jan 20 '13 at 04:16
  • 3
    A self type can also be a class, but a trait cannot inherit from a class. – cvogt Jun 22 '13 at 01:54
  • 10
    @cvogt: a trait can inherit from a class (at least as of 2.10): http://pastebin.com/zShvr8LX – Erik Kaplun Mar 14 '14 at 15:59
  • 1
    @Blaisorblade: isn't that something that could be solved by a small language re-design, though, and not a fundamental limitation? (at least from the point of view of the question) – Erik Kaplun Mar 14 '14 at 16:00
  • @ErikAllik: I've learned about this limitation from the paper describing the cake pattern, "scalable component abstractions", so I doubt that's an accident. I suspect the rationale is simply due to limitations of the JVM, rather than deep motivations, but that doesn't necessarily mean a fix is possible. – Blaisorblade Mar 14 '14 at 23:57
  • I found this self-type very useful to impose to classes implementing a trait that they extends a (sealed) _trait-Enum_. See this: http://stackoverflow.com/q/36066238/1206998 – Juh_ Mar 17 '16 at 17:09

11 Answers11

282

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, then B is an A. When you use self-types, B requires an A. There are two specific requirements that are created with self-types:

  1. If B is extended, then you're required to mix-in an A.
  2. When a concrete class finally extends/mixes-in these traits, some class/trait must implement A.

Consider the following examples:

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

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

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

If Tweeter was a subclass of User, there would be no error. In the code above, we required a User whenever Tweeter is used, however a User wasn't provided to Wrong, so we got an error. Now, with the code above still in scope, consider:

scala> trait DummyUser extends User {
     |   override def name: String = "foo"
     | }
defined trait DummyUser

scala> trait Right extends Tweeter with User {
     |   val canDo = name
     | }
defined trait Right 

scala> trait RightAgain extends Tweeter with DummyUser {
     |   val canDo = name
     | }
defined trait RightAgain

With Right, the requirement to mix-in a User is satisfied. However, the second requirement mentioned above is not satisfied: the burden of implementing User still remains for classes/traits which extend Right.

With RightAgain both requirements are satisfied. A User and an implementation of User are provided.

For more practical use cases, please see the links at the start of this answer! But, hopefully now you get it.

Cory Klein
  • 40,647
  • 27
  • 164
  • 222
Daniel C. Sobral
  • 284,820
  • 82
  • 479
  • 670
  • 3
    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 Jan 03 '10 at 02:40
  • 29
    @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 C. Sobral Jan 03 '10 at 04:14
  • 10
    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 Jan 03 '10 at 06:16
  • @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 C. Sobral Jan 04 '10 at 00:54
  • The second trait should read "this: User =>" instead of "user: User =>" – Rodney Gitzel Jan 19 '11 at 01:14
  • 11
    @Rodney No, it shouldn't. In fact, using `this` with self types is something I look down upon, since it shadows for no good reason the original `this`. – Daniel C. Sobral Jan 19 '11 at 10:56
  • 1
    Hmmm. Ah, my bad, when I pasted "user:" I got a pasting error, not a compiling error. But that begs a question of why even bother to name the self-type? To resolve ambiguities, I guess: "user.name" can be used instead of just "name". So definitely using "this" is a bad idea... how would you access the real this? – Rodney Gitzel Jan 19 '11 at 18:07
  • The url of the article that Mushtaq posted has changed slightly: http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/ – Andrew E Jul 01 '12 at 03:03
  • Excellent answer, BTW, how can you express more than one dependency? I tried with (dep1: Dep1, dep2: Dep2) => { xxx }, and it compiles, but it doesn't check for the dependencies... – opensas Nov 25 '12 at 15:18
  • 9
    @opensas Try `self: Dep1 with Dep2 =>`. – Daniel C. Sobral Dec 03 '12 at 19:51
  • so, @DanielC.Sobral, adding `... with User` to `trait Wrong extends Tweeter` will fix this issue since using the `self-trait` means that it **must** have a `User`? – Kevin Meredith Jan 08 '15 at 18:56
  • Thank you for this answer! Could someone point out the difference between writing `user: User =>`, `self: User =>` and `this: User =>`? – Ivaylo Toskov Feb 20 '17 at 14:53
  • @IvayloToskov they are nearly identical. They all require the type of `this` to be `User`, but they optionally also introduce the `user` or `self` identifier as an alias for `this`. So with `trait Tweeter { user: User =>` you can write `user.name` in addition to `this.name` inside `Tweeter`. – BrunoMedeiros Jul 26 '17 at 12:16
  • @DanielC.Sobral I don't think your answer is correct: You said "When you do dependency injection, you want B to require A, not to be an A. " - well, that might be true for DI in general, but not for the self-type syntax being discussed here. Namely, in your example: `trait Tweeter { user: User => // ... `, the self-type declaration _does require_ concrete types implementing `Tweeter` to _be a_ `User` too (similar to having `trait Tweeter extends User` instead). That's why `trait Wrong extends Tweeter` is an error, but `trait Wrong extends Tweeter with User {` works. – BrunoMedeiros Jul 26 '17 at 12:29
  • The article changed URL again: http://jonasboner.com/real-world-scala-dependency-injection-di/ – ari gold Apr 25 '18 at 17:28
  • keep your answers short or add tl;dr @jazmit's answer bellow can give you a clue – MaxNevermind Jul 21 '18 at 10:02
159

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.

Jacek Laskowski
  • 64,943
  • 20
  • 207
  • 364
Mushtaq Ahmed
  • 6,182
  • 2
  • 16
  • 14
  • 3
    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 Jan 03 '10 at 02:36
  • 4
    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 Jan 03 '10 at 13:19
  • 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 Jan 04 '10 at 01:35
  • @DanielC.Sobral may be thanks to your comment but at the moment it has more upvotes than your anser. Upvoting both :) – rintcius Sep 14 '12 at 17:41
  • Why not just create one trait AB? As traits A and B must always be combined in any final class, why separate them in the first place? – Rich Oliver Nov 04 '19 at 23:22
  • @RichOliver I guess the answer is that you simlpy don't control each and every trait in the universe. – Kevin Dreßler Jul 16 '20 at 11:43
58

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.

kostja
  • 56,537
  • 45
  • 164
  • 213
Dave Griffith
  • 20,025
  • 3
  • 51
  • 74
  • 41
    Actually you can use inheritance with structural types too: abstract class A extends {def close:Unit} – Adrian Mar 22 '11 at 02:14
  • 12
    I think structural typing is using reflection, so use only when there is no other choice... – Eran Medan Jul 08 '13 at 13:50
  • @Adrian, I believe your comment is incorrect. ` abstract class A extends {def close:Unit}` is just an abstract class with Object superclass. it's just a Scala's permissive syntax to nonsensical expressions. You can ` class X extends { def f = 1 }; new X().f` for example – Alexey Jun 13 '16 at 21:00
  • 1
    @Alexey I don't see why is your example (or mine) nonsensical. – Adrian Jul 08 '16 at 23:06
  • 1
    @Adrian, `abstract class A extends {def close:Unit}` is equivalent to `abstract class A {def close:Unit}` . So it does not involve structural types. – Alexey Jul 09 '16 at 10:28
15

Another thing that has not been mentioned: because self-types aren't part of the hierarchy of the required class they can be excluded from pattern matching, especially when you are exhaustively matching against a sealed hierarchy. This is convenient when you want to model orthogonal behaviors such as:

sealed trait Person
trait Student extends Person
trait Teacher extends Person
trait Adult { this : Person => } // orthogonal to its condition

val p : Person = new Student {}
p match {
  case s : Student => println("a student")
  case t : Teacher => println("a teacher")
} // that's it we're exhaustive
Bruno Bieth
  • 2,087
  • 18
  • 30
13

Section 2.3 "Selftype Annotations" of Martin Odersky's original Scala paper Scalable Component Abstractions actually explains the purpose of selftype beyond mixin composition very well: provide an alternative way of associating a class with an abstract type.

The example given in the paper was like the following, and it doesn't seem to have an elegant subclass correspondent:

abstract class Graph {
  type Node <: BaseNode;
  class BaseNode {
    self: Node =>
    def connectWith(n: Node): Edge =
      new Edge(self, n);
  }
  class Edge(from: Node, to: Node) {
    def source() = from;
    def target() = to;
  }
}

class LabeledGraph extends Graph {
  class Node(label: String) extends BaseNode {
    def getLabel: String = label;
    def self: Node = this;
  }
}
lcn
  • 1,831
  • 20
  • 40
  • For those wondering why subclassing won't solve this, Section 2.3 also says this: “Each of the operands of a mixin composition C_0 with ... with C_n, must refer to a class. The mixin composition mechanism does not allow any C_i to refer to an abstract type. This restriction makes it possible to statically check for ambiguities and override conflicts at the point where a class is composed.” – Luke Maurer Jul 28 '17 at 18:19
11

TL;DR summary of the other answers:

  • Types you extend are exposed to inherited types, but self-types are not

    eg: class Cow { this: FourStomachs } allows you to use methods only available to ruminants, such as digestGrass. Traits that extend Cow however will have no such privileges. On the other hand, class Cow extends FourStomachs will expose digestGrass to anyone who extends Cow .

  • self-types allow cyclical dependencies, extending other types does not

Community
  • 1
  • 1
jazmit
  • 4,464
  • 25
  • 36
10

Let's start with the cyclical dependency.

trait A {
  selfA: B =>
  def fa: Int }

trait B {
  selfB: A =>
  def fb: String }

However, the modularity of this solution is not as great as it might first appear, because you can override self types as so:

trait A1 extends A {
  selfA1: B =>
  override def fb = "B's String" }
trait B1 extends B {
  selfB1: A =>
  override def fa = "A's String" }
val myObj = new A1 with B1

Although, if you override a member of a self type, you lose access to the original member, which can still be accessed through super using inheritance. So what is really gained over using inheritance is:

trait AB {
  def fa: String
  def fb: String }
trait A1 extends AB
{ override def fa = "A's String" }        
trait B1 extends AB
{ override def fb = "B's String" }    
val myObj = new A1 with B1

Now I can't claim to understand all the subtleties of the cake pattern, but it strikes me that the main method of enforcing modularity is through composition rather than inheritance or self types.

The inheritance version is shorter, but the main reason I prefer inheritance over self types is that I find it much more tricky to get the initialisation order correct with self types. However, there are some things you can do with self types that you can't do with inheritance. Self types can use a type while inheritance requires a trait or a class as in:

trait Outer
{ type T1 }     
trait S1
{ selfS1: Outer#T1 => } //Not possible with inheritance.

You can even do:

trait TypeBuster
{ this: Int with String => }

Although you'll never be able to instantiate it. I don't see any absolute reason for not being be able to inherit from a type, but I certainly feel it would be useful to have path constructor classes and traits as we have type constructor traits / classes. As unfortunately

trait InnerA extends Outer#Inner //Doesn't compile

We have this:

trait Outer
{ trait Inner }
trait OuterA extends Outer
{ trait InnerA extends Inner }
trait OuterB extends Outer
{ trait InnerB extends Inner }
trait OuterFinal extends OuterA with OuterB
{ val myV = new InnerA with InnerB }

Or this:

  trait Outer
  { trait Inner }     
  trait InnerA
  {this: Outer#Inner =>}
  trait InnerB
  {this: Outer#Inner =>}
  trait OuterFinal extends Outer
  { val myVal = new InnerA with InnerB with Inner }

One point that should be empathised more is that traits can extends classes. Thanks to David Maclver for pointing this out. Here's an example from my own code:

class ScnBase extends Frame
abstract class ScnVista[GT <: GeomBase[_ <: TypesD]](geomRI: GT) extends ScnBase with DescripHolder[GT] )
{ val geomR = geomRI }    
trait EditScn[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
trait ScnVistaCyl[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]

ScnBase inherits from the Swing Frame class, so it could be used as a self type and then mixed in at the end (at instantiation). However, val geomR needs to be initialised before it's used by inheriting traits. So we need a class to enforce prior initialisation of geomR. The class ScnVista can then be inherited from by multiple orthogonal traits which can themselves be inherited from. Using multiple type parameters (generics) offers an alternative form of modularity.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Rich Oliver
  • 5,653
  • 4
  • 32
  • 52
7
trait A { def x = 1 }
trait B extends A { override def x = super.x * 5 }
trait C1 extends B { override def x = 2 }
trait C2 extends A { this: B => override def x = 2}

// 1.
println((new C1 with B).x) // 2
println((new C2 with B).x) // 10

// 2.
trait X {
  type SomeA <: A
  trait Inner1 { this: SomeA => } // compiles ok
  trait Inner2 extends SomeA {} // doesn't compile
}
Oleg Galako
  • 1,016
  • 1
  • 10
  • 16
4

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.

Blaisorblade
  • 6,172
  • 40
  • 69
kikibobo
  • 1,087
  • 1
  • 8
  • 8
  • 3
    @Blaisorblade: I wonder whether you might have misread kikibobo's answer -- a trait's self type does indeed allow you to constrain the types that may mix it in, and that is part of its usefulness. For example, if we define `trait A { self:B => ... }` then a declaration `X with A` is only valid if X extends B. Yes, you can say `X with A with Q`, where Q does not extend B, but I believe kikibobo's point was that X is so constrained. Or did I miss something? – AmigoNico Jan 20 '13 at 02:34
  • 1
    Thanks, you're right. My vote was locked, but luckily I could edit the answer and then change my vote. – Blaisorblade Jan 20 '13 at 04:08
2

Update: A principal difference is that self-types can depend on multiple classes (I admit that's a bit corner case). For example, you can have

class Person {
  //...
  def name: String = "...";
}

class Expense {
  def cost: Int = 123;
}

trait Employee {
  this: Person with Expense =>
  // ...

  def roomNo: Int;

  def officeLabel: String = name + "/" + roomNo;
}

This allows to add the Employee mixin just to anything that is a subclass of Person and Expense. Of course, this is only meaningful if Expense extends Person or vice versa. The point is that using self-types Employee can be independent of the hierarchy of the classes it depends on. It doesn't care of what extends what - If you switch the hierarchy of Expense vs Person, you don't have to modify Employee.

Petr
  • 60,177
  • 8
  • 136
  • 295
  • Employee does not need to be a class to descend from Person. Traits can extend classes. If the Employee trait extended Person instead of using a self type, the example would still work. I find your example interesting, but it doesn't seem to illustrate a use case for self types. – Morgan Creighton Oct 15 '12 at 23:58
  • @MorganCreighton Fair enough, I didn't know that traits can extend classes. I'll think about it if I can find a better example. – Petr Oct 16 '12 at 04:58
  • 1
    Yes, it's a surprising language feature. If trait Employee extended class Person, then whatever class ultimately "withed in" Employee would also have to extend Person. But that restriction is still present if Employee used a self type instead of extending Person. Cheers, Petr! – Morgan Creighton Oct 18 '12 at 13:06
  • 1
    I don't see why "this is only meaningful if Expense extends Person or vice versa." – Robin Green May 31 '15 at 12:02
0

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
  • 25,561
  • 25
  • 109
  • 173
  • No, B can be (and indeed is) an "abstract trait" in both cases. So there is no difference from that perspective. – Robin Green May 31 '15 at 12:04