Traits: Using Traits As Interfaces

At their most basic level, traits can be used as simple interfaces. Like classes, traits can contain members, which are methods and fields. Members can be:

  • Abstract
  • Concrete

In this lesson we’ll just look at abstract members, and see how to use those as we “mix them” into classes, which will provide implementations for them.

Members are public by default --- publicly accessible --- and we’ll use them that way in this lesson.

Example of traits as interfaces

trait HasTail:
    def startTail(): Unit
    def stopTail(): Unit

trait CanSpeak:
    def speak(): Unit

class Dog extends HasTail, CanSpeak:
    def startTail(): Unit = println("Tail is wagging")
    def stopTail(): Unit = println("Tail is stopped")
    def speak(): Unit = println("Woof")

val d = Dog()
d.speak()
d.startTail()
d.stopTail()

One benefit of traits as interfaces

Could write this to take a Dog, but it’s more flexible to just accept the CanSpeak type:

def saySomething(speaker: CanSpeak) = speaker.speak()

For instance, now if you also have a Cat:

class Cat extends CanSpeak:
    def speak(): Unit = println("Meow")

you can do this:

saySomething(Dog())
saySomething(Cat())

Extracting interfaces from classes

You can also work the other way around. You might first create a Dog class:

class Dog:
    def startTail = println("Tail is wagging")
    def stopTail = println("Tail is stopped")
    def speak = println("Woof")

And then a Cat class:

class Dog:
    def startTail = println("Tail is wagging")
    def stopTail = println("Tail is stopped")
    def speak = println("Meow")

And then you would see the common functionality between Dog and Cat, and extract the HasTail and CanSpeak interfaces, ending up at the same solution.