Why are aliases for self types needed?

The self reference in the body of trait T { self: Q => ... } is an alias for this. Why does the language allow introducing an alias, and why is this ever useful? Why not always write trait T { this: Q => ... }?

1 Like

If you have an inner class/trait and you want to access a property of the outer class your code gets a lot nicer with a self alias.

scala> trait Foo {
     |   def id = 1
     |   def inner = new Foo {
     |     override def id = this.id + 1 // this is THIS instance not the outer one
     |   }
     | }
defined trait Foo

scala> new Foo{}.inner.inner.id
<oops stackoverflow>

scala> trait Foo { outer =>
     |   def id = 1
     |   def inner = new Foo {
     |     override def id = outer.id + 1
     |   }
     | }
defined trait Foo

scala> new Foo{}.inner.inner.id
res0: Int = 3

You could also write Foo.this.id like you would in java, but let’s face it, that’s just awful :stuck_out_tongue:

1 Like

An alias of the self reference in traits is useful for avoiding ambiguities
in inheritance.

Hello,

I thought the reason was that self has a different type than this.

 Best, Oliver

In a trait, self refers to the trait. this refers to the instance of the
class that inherits the trait.

In a trait, self refers to the trait. this refers to the instance of the
class that inherits the trait.

Can you explain what that means? Are the two not identical references? What code is valid for one but not the other?

The SLS section 5.1 says:

The sequence of template statements may be prefixed with a formal parameter definition and an arrow, e.g. x =>, or x:T =>. If a formal parameter is given, it can be used as an alias for the reference this throughout the body of the template.

I read “alias” to mean they’re identical.

I think you might be conflating two different concepts. Let me see if I can answer your question… In essence, a self type does two things:

Requires classes extending the trait to be of a certain type.

Let’s take this example…

trait Database {
  impl: DbImpl =>

  ....
}

In the example above, you can only extend Database if the class that extends it is an instance of DbImpl. If you tried to do anything else the compiler would yell at you.

Lets you reference members of the subtype

Normally, when you’re writing a trait, you can only access the other things you define in the trait. When you define a self type you can also access things defined in the class that defines the trait. For example:

trait DbImpl {
  def identifier: String
}

trait Database {
  impl: DbImpl =>

  def getIdentifier() = impl.identifier
}

Back to the SLS quote

Back to the bit you quoted from the SLS…

I believe the crux of what you saw means that the following is possible…

trait Database {
  this: DbImpl =>
}

Normally if you use this in a trait I believe you’re referencing the trait itself. The use of this construct means that inside the trait the this keyword is changed to reference the DbImpl mixing in the trait, not the trait itself.

Does that make sense?

Just re-read your original question and realized I may have explained some stuff you already understood… hehe.

The reason being able to alias this is useful is simply for convenience purposes as far as I know. You can use other identifiers if you want to reference the class you’re mixing in as I did in my example above. =)