Channing Walton
Channing Walton

Reputation: 4007

Fixing abstract types in self type

Consider this:

object TypeProblem {

  trait A {
    type T
    val set = Set[T]()
  }

  trait B {
    def b()
  }

  trait FooBad { this: A =>
    type T <: B
    def x {
      set.foreach(_.b())
    }
  }

  trait FooOk { this: A =>
    type MyT <: B
    type T = MyT

    def x {
      set.foreach(_.b())
    }
  }

}

The compiler complains that value b is not a member of FooBad.this.T So why does FooOk work where I define a new type MyT and assigning T to MyT?

Upvotes: 3

Views: 128

Answers (1)

Iulian Dragos
Iulian Dragos

Reputation: 5712

The self type of FooBad is expanded by the compiler to FooBad with A (so that you can still access the members you define yourself). That means that T gets the definition in A, and not the one in FooBad, as you'd expect. You can fix your code by changing the definition of FooBad to explicitly add your own type:

trait FooBad { this: A with FooBad =>
   ..
}

or even better by using subclassing

trait FooBad extends A {
  ..
}

It is my belief that in most cases self-types should be replaced by plain subclassing. It is simpler to understand, less scary, and leads to better encapsulation.

Upvotes: 4

Related Questions