How to define a Scala trait so it can only be subclassed by a certain type

This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 8.6, “How to define a Scala trait so it can only be subclassed by a certain type.”

Problem

You want to mark a Scala trait so it can only be used by types that extend a certain base type.

Solution

To make sure that a trait named MyTrait can only be mixed into a class that is a subclass of a type named BaseType, begin your trait with a this: BaseType => declaration, as shown here:

trait MyTrait {
    this: BaseType =>

For instance, to make sure a StarfleetWarpCore can only be used in a Starship, mark the StarfleetWarpCore trait like this:

trait StarfleetWarpCore {
    this: Starship =>
    // more code here ...
}

Given that declaration, this code will work:

class Starship
class Enterprise extends Starship with StarfleetWarpCore

But other attempts like this will fail:

class RomulanShip

// this won't compile
class Warbird extends RomulanShip with StarfleetWarpCore

This second example fails with an error message similar to this:

error: illegal inheritance;
self-type Warbird does not conform to StarfleetWarpCore's selftype ↵
StarfleetWarpCore with Starship
class Warbird extends RomulanShip with StarfleetWarpCore
                                       ^

Discussion

As shown in the error message, this approach is referred to as a Scala self type. The Scala Glossary includes this statement as part of its description of a self type:

“Any concrete class that mixes in the trait must ensure that its type conforms to the trait’s self type.”

A trait can also require that any type that wishes to extend it must extend multiple other types. The following WarpCore definition requires that any type that wishes to mix it in must extend WarpCoreEjector and FireExtinguisher, in addition to extending Starship:

trait WarpCore {
    this: Starship with WarpCoreEjector with FireExtinguisher =>
}

Because the following Enterprise definition matches that signature, this code compiles:

class Starship
trait WarpCoreEjector
trait FireExtinguisher

// this works
class Enterprise extends Starship
      with WarpCore
      with WarpCoreEjector
      with FireExtinguisher

But if the Enterprise doesn’t extend Starship, WarpCoreEjector, and FireExtinguisher, the code won’t compile. Once again, the compiler shows that the self-type signature is not correct:

// won't compile
class Enterprise extends Starship with WarpCore with WarpCoreEjector

error: illegal inheritance;
self-type Enterprise does not conform to WarpCore's selftype WarpCore
with Starship with WarpCoreEjector with FireExtinguisher
class Enterprise extends Starship with WarpCore with WarpCoreEjector
                                       ^

See Also