views:

253

answers:

3

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?

+3  A: 

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:

trait FooService

trait FooRemoting { this : FooService => }
trait FooPersistence { this : FooService => }

object Services extends FooService with FooRemoting with FooPersistence

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:

trait Iterator[T] {
  def hasNext : boolean
  def next : T
}

trait InfiniteIterator[T] extends Iterator[T] {
  def hasNext = true
}
Viktor Klang
+2  A: 

Self type annotations allow you to express cyclic dependencies. For instance:

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

This is not possible with simple inheritance.

Joa Ebert
+1  A: 

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.

In conclusion, if we want to move method implementations inside traits then we risk polluting the interface of those traits with abstract methods that support the implementation of the concrete methods and are unrelated with the main responsibility of the trait. A solution to this problem is to move those abstract methods in other traits and compose the traits together using self type annotations and multiple inheritance.

For example:

trait PublicInterface { this: HelperTrait =>
  // Uses helperMethod
}

trait HelperTrait {
  def helperMethod = // ...
}

class ImplementationClass extends PublicInterface with HelperTrait

A Tour of Scala discusses using self type annotations with abstract type members - presumably it's not possible to extend an abstract type member(?)

Ben Lings