8.6. Marking Traits So They Can Only Be Used by Subclasses of a Certain Type

Problem

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

Solution

To make sure 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 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 ...

Get Scala Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.