Jun 052011
 

Quick refresher: self-types are commonly used when writing traits that want to proscribe that they get mixed in to a particular class. For example, the cake-pattern leverages them. In the example below, FooTrait specifies a self-type of FooTraitConfiguration to insure that it is mixed in to a class that provides the expected times val.

import actors.Actor
import actors.Actor._

trait FooTraitConfiguration { val times : Int }

trait FooTrait { self:FooTraitConfiguration =>
  case object Ping
  case object Pong

  val a = actor {
    loop {
      react {
        case Ping =>
          self ! Pong
        case Pong =>
          for(_ <- (1 to times)) { print(".") }
          System.out.println("pong.")
  } } }

  def ping = a ! Ping
  def pong = a ! Pong
}

class Foo extends FooTrait with FooTraitConfiguration { @Override val times = 5 }

But, alas, this fails to compile:

error: value ! is not a member of FooTrait with FooTraitConfiguration
self ! Pong

It seems that the self-trait has broken the Actor API! And indeed, it has. Because self-traits are not usually specified with self! It should have been:
this:FooTraitConfiguration =>

The self-type means that within FooTrait the type of this is considered to be FooTrait with FooTraitConfiguration. Using a word other than this additionally sets up an alias to that type for e.g. use within nested classes. And there’s the rub: Actors depend on a method named self which is shadowed when the alias to the type is named self.

Note to self: Don’t use self when specifying self types!