This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 8.1, “How to use a Scala trait as an interface.”
Problem
You’re used to creating interfaces in other languages like Java, and want to create something like that in Scala.
Solution
You can use a Scala trait
just like a Java interface
. As with interfaces, just declare the methods in your trait that you want extending classes to implement:
trait BaseSoundPlayer { def play def close def pause def stop def resume }
If the methods don’t take any argument, you only need to declare the names of the methods after the def
keyword, as shown. If a method should require parameters, list them as usual:
trait Dog { def speak(whatToSay: String) def wagTail(enabled: Boolean) }
When a class extends a trait, it uses the extends
and with
keywords. When extending one trait, use extends
:
class Mp3SoundPlayer extends BaseSoundPlayer { ...
When extending a class and one or more traits, use extends
for the class, and with
for subsequent traits:
class Foo extends BaseClass with Trait1 with Trait2 { ...
When a class extends multiple traits, use extends
for the first trait, and with
for subsequent traits:
class Foo extends Trait1 with Trait2 with Trait3 with Trait4 { ...
Unless the class implementing a trait is abstract, it must implement all of the abstract trait
methods:
class Mp3SoundPlayer extends BaseSoundPlayer { def play { // code here ... } def close { // code here ... } def pause { // code here ... } def stop { // code here ... } def resume { // code here ... } }
If a class extends a trait but does not implement the abstract methods defined in that trait, it must be declared abstract
:
// must be declared abstract because it does not implement // all of the BaseSoundPlayer methods abstract class SimpleSoundPlayer extends BaseSoundPlayer { def play { ... } def close { ... } }
In other uses, one trait can extend another trait:
trait Mp3BaseSoundFilePlayer extends BaseSoundFilePlayer { def getBasicPlayer: BasicPlayer def getBasicController: BasicController def setGain(volume: Double) }
Discussion
As demonstrated, at their most basic level, traits can be used just like Java interfaces. In your trait, just declare the methods that need to be implemented by classes that want to extend your trait.
Classes extend your trait using either the extends
or with
keywords, according to these simple rules:
- If a class extends one trait, use the
extends
keyword. - If a class extends multiple traits, use
extends
for the first trait andwith
to extend (mix in) the other traits. - If a class extends a class (or abstract class) and a trait, always use
extends
before the class name, and usewith
before the trait name(s).
You can also use fields in your traits. See the next recipe for examples.
As shown in the WaggingTail
trait in the following example, not only can a trait be used like a Java interface, but it can also provide method implementations, like an abstract class in Java:
abstract class Animal { def speak(): Unit } trait WaggingTail { def startTail() = println("tail started") def stopTail() = println("tail stopped") } trait FourLeggedAnimal { def walk(): Unit def run(): Unit } class Dog extends Animal with WaggingTail with FourLeggedAnimal { // implementation code here ... def speak() = println("Dog says 'woof'") def walk() = println("Dog is walking") def run() = println("Dog is running") }
This ability is discussed in detail in Recipe 8.3, “Using a Trait Like an Abstract Class”.
When a class has multiple traits, such as the WaggingTail
and FourLeggedAnimal
traits in this example, those traits are said to be mixed into the class. The term “mixed in” is also used when extending a single object instance with a trait, like this:
val f = new Foo with Trait1
This feature is discussed more in Recipe 8.8, “Adding a Trait to an Object Instance”.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |