Published 2014-02-08.
Last modified 2016-01-23.
Time to read: 4 minutes.
This is the first of three lectures on Scala Traits.
Scala traits can be pure, which resemble Java 7’s interfaces, or they can have implementations. Traits are ‘mixed in’ to form classes that have a kind of multiple inheritance without the dreaded ‘diamond inheritance’ antipattern that C++ suffers from.
We say that traits are ’mixed in’. Multiple traits can be mixed into a class or object. Trait constructors cannot accept parameters.
The source code for this lecture is provided in courseNotes/src/main/scala/Traits.scala
.
Pure Trait
A pure trait has no implementation and is equivalent to a Java Interface.
Note that I have defined the property in the Checkable
trait below with def
, even though you might expect it to normally
only require a val
.
We discussed why this is a good practice in the
Setters, Getters and the Uniform Access Principle lecture.
import java.sql.Date trait Checkable { def preFlight: Boolean } class Course( startDate: Date = new Date(System.currentTimeMillis), override val preFlight: Boolean = false // override is unnecessary but legal ) extends Checkable { override val toString = s"startDate=$startDate, preFlight=$preFlight" } def isReady(checkable: Checkable): Boolean = checkable.preFlight
It is up to you to decide if you want to decorate val preFlight
with override
or not when overriding an abstract method or
property.
I will not do so any further.
Now let’s create some instances of the class Course
which mixes in the pure trait Checkable
.
scala> val course1 = new Course(Date.valueOf("2014-01-01"), true) course1: Course = Course(2014-01-01,true)
scala> val course2 = new Course() course2: Course = Course(2014-01-05,false)
You can view an instance of a class as an instance of any of its traits.
For example, lets pass a Course
instance to isReady
, which accepts a Checkable
parameter.
scala> isReady(course1) res0: Boolean = true
Trait with Implementation
A trait with an implementation is similar to an abstract class, however traits cannot have a constructor that takes arguments.
Because HasId
is not a pure trait in the following code, classes that mix in
this trait must specify override
if id
is to be mixed in as a property instead of a method.
import java.sql.Date
trait Checkable { def preFlight: Boolean }
trait HasId { def id: Long = 0L }
class Lecture( override val id: Long = 0L, startDate: Date = Date.valueOf("2014-01-01"), val preFlight: Boolean = false ) extends Checkable with HasId { override val toString = s"id=$id, startDate=$startDate, preFlight=$preFlight" }
Now let’s create some instances.
scala> val lecture1 = new Lecture(1L, preFlight=true) lecture1: Lecture = Lecture(1,2014-01-01,true)
scala> val lecture2 = new Lecture() lecture2: Lecture = Lecture(0,2014-01-05,false)
Referring to Supertypes

If you have an instance of a type that is derived from a complex hierarchy of supertypes, you can refer to it as if it were any of the supertypes.
To show what I mean, here are the definitions of types Base
, First
and Holder
.
scala> trait Base { val param1: Int } defined trait Base
scala> abstract class First(val param2: String) defined class First
scala> case class Holder(override val param1: Int, override val param2: String) extends First(param2) with Base defined class Holder
We can create an instance of Holder
:
scala> val bottles: Holder = new Holder(99, "Bottles of beer") bottles: Holder = Holder(99,Bottles of beer)
This instance can be accessed as any of the supertypes:
scala> val base: Base = bottles base: Base = Holder(99,Bottles of beer)
scala> val first: First = bottles first: First = Holder(99,Bottles of beer)
scala> base.param1 res24: Int = 99
scala> first.param2 res25: String = Bottles of beer
You can run this example by typing:
$ sbt "runMain HeirGround"
Extending Multiple Traits
Objects and classes can extend multiple traits.
The first trait or class being extended is mixed in with the keyword extends
.
All other traits are mixed in with the keyword with
.
The order of the traits is significant – in the following example, the type
Shuttle extends Spacecraft with ControlCabin with PulseEngine
is not equivalent to the type
Shuttle extends Spacecraft with PulseEngine with ControlCabin
.
Not only does the order of the mixin determine the type, it also determines the behavior of the resulting class.
There are many traits and a few classes that are combined to make spaceships of various types and capabilities.
Many of these traits define a method called speedUp
.
The order of the mixin matters, and the implementation of the speedUp
method will be provided by the rightmost trait with a concrete
implementation of that method.
Let’s walk through the code.
- The enclosing object,
BoldlyGo
, creates anExplorer
, which we will look at in a moment. - There is an abstract class called
Spacecraft
, which defines a method calledengage
that accepts no parameters and does not return anything. Clearlyengage
is only useful for side effects, so it is written with empty parentheses, which is hint to the reader that this method is ’side-effecty’. - The
Bridge
trait is not a pure trait because itsengage
method has an implementation. ItsspeedUp
method is undefined, but because it is written with empty parentheses we expect that implementations will have side effects. - The
Engine
trait also defines aspeedUp
method. - The
PulseEngine
trait extends theEngine
trait, and it:- Provides an implementation for the
speedUp
method declared inEngine
, and the implementation’s side effect is to set the value ofcurrentPulse
. - Defines a mutable variable of type
Int
calledcurrentPulse
. - Defines an abstract method called
maxPulse
that looks like a getter, because it does not receive any parameters and returns a value, and we don’t expect side effects because it was not defined using paretheses.
- Provides an implementation for the
- The
ControlCabin
trait provides an implementation forengage
and declares anincreaseSpeed
method. - The
Shuttle
class extends theSpacecraft
abstract superclass, mixes inControlCabin
andPulseEngine
, and provides a concrete implementation ofmaxPulse
andincreaseSpeed
. Scala only allows one class or abstract class to be extended when defining a new class, and if mixing in one or more traits as well, the superclass must be mentioned first using theextends
keyword. If a defined class does not inherit from a superclass and only extended traits, then the first trait mixed in would be prefaced with the keywordextends
and the names of the other traits would follow, separated by the keywordwith
.increaseSpeed
invokes thespeedUp
method fromPulseEngine
, not the method of the same name fromControlCabin
becausePulseEngine
was mixed in to the right ofControlCabin
. - The
WarpEngine
trait subclassesEngine
, adding the new abstract methodmaxWarp
, which looks like a getter, the mutablecurrentWarp
variable and a concrete implementation of thespeedUp
method fromEngine
. - Class
Explorer
extends the abstract classSpacecraft
, which must be mentioned before any traits are mixed in. TheBridge
andWarpEngine
traits are then mixed in.Explorer
provides a concrete implementation ofmaxWarp
declared byWarpEngine
and a concrete implementation ofspeedUp
declared byEngine
. - The singleton object
Defiant
is an instance ofExplorer
that also extendsSpacecraft
but mixes in theControlCabin
andWarpEngine
traits instead of theBridge
andWarpEngine
traits that theExplorer
class mixes in.
object BoldlyGo extends App { val explorer = new Explorer println(explorer)
abstract class Spacecraft { def engage(): Unit }
trait Bridge { def speedUp(): Unit def engage(): Unit = { speedUp(); speedUp(); speedUp() } }
trait Engine { def speedUp(): Unit }
trait PulseEngine extends Engine { var currentPulse = 0 def maxPulse: Int def speedUp(): Unit = if (currentPulse < maxPulse) currentPulse += 1 }
trait ControlCabin { def increaseSpeed(): Unit def engage(): Unit = increaseSpeed() }
class Shuttle extends Spacecraft with ControlCabin with PulseEngine { val maxPulse = 10 def increaseSpeed(): Unit = speedUp() }
trait WarpEngine extends Engine { def maxWarp: Int var currentWarp: Int = 0 def toWarp(x: Int): Unit = if (x < maxWarp) currentWarp = x }
class Explorer extends Spacecraft with Bridge with WarpEngine { val maxWarp = 10 def speedUp(): Unit = toWarp(currentWarp + 1) }
object Defiant extends Spacecraft with ControlCabin with WarpEngine { val maxWarp = 20 def increaseSpeed() = toWarp(10) def speedUp(): Unit = toWarp(currentWarp + 2) } }
Traits Should Not Extend Classes

Just because you can do something, does not mean that you should do it. Extending traits with classes would allow multiple inheritance, which has many problems. Here is one example of an error that results from attempting multiple inheritance.
scala> class Animal defined class Animal
scala> trait Furry extends Animal defined trait Furry
scala> class Plant defined class Plant
scala> trait Leafy extends Plant defined trait Leafy scala> trait Chimera extends Leafy with Furry <console>:11: error: illegal inheritance; superclass Plant is not a subclass of the superclass Animal of the mixin trait Furry trait Chimera extends Leafy with Furry ^
© Copyright 1994-2024 Michael Slinn. All rights reserved.
If you would like to request to use this copyright-protected work in any manner,
please send an email.
This website was made using Jekyll and Mike Slinn’s Jekyll Plugins.