How to declare that a Scala trait can only be mixed into a type that has a specific method

This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 8.7, “How to declare that a Scala trait can only be mixed into a type that has a specific method.”

Problem

You only want to allow a trait to be mixed into a type (class, abstract class, or trait) that has a method with a given signature.

Solution

Use a variation of the self-type syntax that lets you declare that any class that attempts to mix in the trait must implement the method you specify.

In the following example, the WarpCore trait requires that any classes that attempt to mix it in must have an ejectWarpCore method:

trait WarpCore {
    this: { def ejectWarpCore(password: String): Boolean } =>
}

It further states that the ejectWarpCore method must accept a String argument and return a Boolean value.

The following definition of the Enterprise class meets these requirements, and will therefore compile:

class Starship {
    // code here ...
}

class Enterprise extends Starship with WarpCore {
    def ejectWarpCore(password: String): Boolean = {
        if (password == "password") {
            println("ejecting core")
            true
        } else {
            false
        }
    }
}

A trait can also require that a class have multiple methods. To require more than one method, just add the additional method signatures inside the block:

trait WarpCore {
    this: {
        def ejectWarpCore(password: String): Boolean
        def startWarpCore: Unit
    } =>
}

class Starship
class Enterprise extends Starship with WarpCore {
    def ejectWarpCore(password: String): Boolean = {
        if (password == "password") { println("core ejected"); true } else false
    }
    def startWarpCore { println("core started") }
}

Discussion

This approach is known as a structural type, because you’re limiting what classes the trait can be mixed into by stating that the class must have a certain structure, i.e., the methods you’ve defined. In the examples shown, limits were placed on what classes the WarpCore trait can be mixed into.

See Also