http://image.motortrend.com/f/features/consumer/1301_chevrolet_corvette_60_years_american_icon_part_1/42023018/1961-Chevrolet-Corvette-front.jpg

SCALA SELF-TYPES
Gregor Heine, Gilt Groupe
Lets build a car...
Components
●
●
●
●
●
●
●
●

Engine
Fuel Tank
Wheels
Gearbox
Steering
Accelerator
Clutch
etc...
OK, let's write some interfaces
trait Engine {
def start(): Unit
def stop(): Unit
def isRunning(): Boolean
def fuelType: FuelType
}
trait Car {
def drive(): Unit
def park(): Unit
}
Well actually, in Scala we can also
add some implementation
trait Engine {
private var running = false
def start(): Unit = {
if (!running) println("Engine started")
running = true
}
def stop(): Unit = {
if (running) println("Engine stopped")
running = false
}
def isRunning(): Boolean = running
def fuelType: FuelType
}
trait DieselEngine extends Engine {
override val fuelType = FuelType.Diesel
}
Fine, so how do we put an
Engine into a Car?
First attempt:
Inheritance-based assembly
trait Car extends Engine {
def drive() {
start()
println("Vroom vroom")
}
def park() {
if (isRunning() ) println("Break!")
stop()
}
}
val myCar = new Car extends DieselEngine
Hmm, this isn't great:
A Car is also an Engine
:(
This should really be a has-a relation,
right?
Second attempt:
Composition-based assembly
trait Car {
def engine : Engine
def drive() {
engine.start()
println("Vroom vroom")
}
def park() {
if (engine.isRunning() ) println("Break!")
engine.stop()
}
}
val myCar = new Car {
override val engine = new DieselEngine()
}
Hmm OK, a Car has an Engine.
That's better.
But...
There is no guarantee that the
Engine in myCar isn't used in
another Car!
:(
If only there was a way to "mix-in" an
Engine into my car rather than supplying
it from the outside
Enter: self-types
“A self type of a trait is the assumed type of this,
the receiver, to be used within the trait. Any
concrete class that mixes in the trait must ensure
that its type conforms to the trait’s self type.”
Programming in Scala
Erm, what, what, what?
Fine, let's look at an example:
trait Car {
this: Engine => // self-type
def drive() {
start()
println("Vroom vroom")
}
def park() {
println("Break!")
stop()
}

}
object MyCar extends Car with DieselEngine
trait Car {
this: Engine => // self-type
def drive() {

Looks a bit like composition-based assembly

start()
println("Vroom vroom")
}
def park() {
println("Break!")
stop()
}

Looks like inheritance-based assembly

}
object MyCar extends Car with DieselEngine
So what's happening here?
● Self-types are used with traits
● Explicitly declare the type of the value this
● Specify the requirements on any concrete class
or instance the trait is mixed into.
● Declare a dependency of the trait on another
type: “In order to use me you have to be one of
those”
So, tell me more about self-types
No need to call the self-type "this"
You can use this-aliasing to give it a
different name:
trait Car {
engine: Engine =>
def drive() {
engine.start()
println("Vroom vroom")
}
}

Useful for nested classes or traits, where accessing
a particular this would otherwise be difficult
Self-types don’t automatically inherit:
trait HondaCar extends Car
// error: self-type HondaCar does not conform to Car's selftype Car
with Engine

Need to repeat the self-type in subtypes:
trait HondaCar extends Car {
this: Engine =>
// ...
}
A self-type can require multiple types:
trait Car {
this: Engine with FuelTank with GearBox =>
// ...
}

Used when the trait has multiple dependencies
The self-type can be a structural type:
trait Car {
this: {
def start: Unit
def stop: Unit
} =>
// ...
}

Allows for safe mixins with duck-typing.
(Useful when interacting with external dependencies)
So all is good with self-types?
Hmm, well no:
val myCar = new Car extends DieselEngine {}

myCar is still a Car and an Engine
:(
So here's a quick fix:
val myCar: Car = new Car extends DieselEngine {}

… but that's cheating (a bit)!
And it doesn't work for singletons:
object MyCar extends Car with DieselEngine
What we need is a way to wire up and assemble
our components without changing their identity
Enter: The Cake Pattern
Ok, so here's the recipe:
For each component in our system, supply a
Component trait, that declares:
● Any dependent components, using self-types
● A trait describing the component's interface
● An abstract val that will be instantiated with
an instance of the component
● Optionally, implementations of the
component interface
trait EngineComponent {
trait Engine {
private var running = false
def start(): Unit = { /* as before */ }
def stop(): Unit = {/* as before */ }
def isRunning: Boolean = running
def fuelType: FuelType
}
protected val engine : Engine
protected class DieselEngine extends Engine {
override val fuelType = FuelType.Diesel
}
}
trait CarComponent {
this: EngineComponent => // gives access to engine
trait Car {
def drive(): Unit
def park(): Unit
}
protected val car: Car
protected class HondaCar extends Car {
override def drive() {
engine.start()
println("Vroom vroom")
}
override def park() { … }
}
}
Great, now let's tie it all together:
(remember a Car has a couple more components beside an Engine)
object App extends CarComponent with EngineComponent with
FuelTankComponent with GearboxComponent {
override protected val engine = new DieselEngine()
override protected val fuelTank = new FuelTank(capacity = 60)
override protected val gearBox = new FiveGearBox()
override val car = new HondaCar()
}
MyApp.car.drive()
MyApp.car.park()
If we want to write a CarTest, we can
provide mock instances for the
components we're not testing:
val testCar = new CarComponent with EngineComponent with FuelTankComponent
with GearboxComponent {
override protected val engine = mock[Engine]

// mock engine

override protected val fuelTank = mock[FuelTank]

// mock tank

override protected val gearBox = new FiveGearBox() // an actual gearbox
override val car = new HondaCar()
}.car
Time to recap
The Cake Pattern
+ Environment specific assembly of components
+ Compile-time checked, typesafe
+ Everything is immutable
+ No external DI descriptor
- Can become hard to read and understand
- May be difficult to configure components
- No control over initialization order
- Self-types prone to fragile base class problem
Remember this:
trait Car {
engine: Engine =>
def drive() { /* start engine */ }
def park() { /* stop engine */ }
}
object MyCar extends Car with DieselEngine

How did they do it?
Let's decompile MyCar.class
> javap com.example.MyCar
Compiled from "Car.scala"
public final class com.example.MyCar extends java.lang.Object{
public static void park();
public static void drive();
public static boolean isRunning();
public static void stop();
public static void start();
/* … */
}

All functions from Car and Engine have been
"lifted" into the top-level class!
Imagine Car and Engine are part of a library that
I'm using to construct MyCar.
Any change to library-private interactions
between these traits are not reflected in MyCar.
class
http://4.bp.blogspot.com/-OHTIQo-k2_k/Tmjkj66eIYI/AAAAAAAACfY/n1Vj1fseVQ0/s1600/Boom.jpg
Ergo:
Be very careful exposing self-types
as part of a library
Fin.
Sources:
●
●
●
●
●
●
●
●
●

M. Odersky, L. Spoon, B. Venners: Programming in Scala, 2nd Edition
C. S. Horstmann: Scala for the Impatient
M. Odersky: Scalable Component Abstractions
http://lampwww.epfl.ch/~odersky/papers/ScalableComponent.pdf
J. Bonér: Real-World Scala: Dependency Injection (DI)
http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di
A Tour of Scala: Explicitly Typed Self References
http://www.scala-lang.org/old/node/124
Cake pattern in depth
http://www.cakesolutions.net/teamblogs/2011/12/19/cake-pattern-in-depth
Dependency Injection In Scala using Self Type Annotations
http://blog.knoldus.com/2013/01/21/dependency-injection-in-scala-using-self-type-annotations
Cake Pattern in Scala / Self type annotations / Explicitly Typed Self References - explained
https://coderwall.com/p/t_rapw
DI in Scala: Cake Pattern pros & cons
http://www.warski.org/blog/2011/04/di-in-scala-cake-pattern-pros-cons

Scala Self Types by Gregor Heine, Principal Software Engineer at Gilt

  • 1.
  • 2.
  • 3.
  • 4.
    OK, let's writesome interfaces
  • 5.
    trait Engine { defstart(): Unit def stop(): Unit def isRunning(): Boolean def fuelType: FuelType } trait Car { def drive(): Unit def park(): Unit }
  • 6.
    Well actually, inScala we can also add some implementation
  • 7.
    trait Engine { privatevar running = false def start(): Unit = { if (!running) println("Engine started") running = true } def stop(): Unit = { if (running) println("Engine stopped") running = false } def isRunning(): Boolean = running def fuelType: FuelType } trait DieselEngine extends Engine { override val fuelType = FuelType.Diesel }
  • 8.
    Fine, so howdo we put an Engine into a Car?
  • 9.
  • 10.
    trait Car extendsEngine { def drive() { start() println("Vroom vroom") } def park() { if (isRunning() ) println("Break!") stop() } } val myCar = new Car extends DieselEngine
  • 11.
    Hmm, this isn'tgreat: A Car is also an Engine :( This should really be a has-a relation, right?
  • 12.
  • 13.
    trait Car { defengine : Engine def drive() { engine.start() println("Vroom vroom") } def park() { if (engine.isRunning() ) println("Break!") engine.stop() } } val myCar = new Car { override val engine = new DieselEngine() }
  • 14.
    Hmm OK, aCar has an Engine. That's better. But...
  • 15.
    There is noguarantee that the Engine in myCar isn't used in another Car! :(
  • 16.
    If only therewas a way to "mix-in" an Engine into my car rather than supplying it from the outside Enter: self-types
  • 17.
    “A self typeof a trait is the assumed type of this, the receiver, to be used within the trait. Any concrete class that mixes in the trait must ensure that its type conforms to the trait’s self type.” Programming in Scala
  • 18.
    Erm, what, what,what? Fine, let's look at an example:
  • 19.
    trait Car { this:Engine => // self-type def drive() { start() println("Vroom vroom") } def park() { println("Break!") stop() } } object MyCar extends Car with DieselEngine
  • 20.
    trait Car { this:Engine => // self-type def drive() { Looks a bit like composition-based assembly start() println("Vroom vroom") } def park() { println("Break!") stop() } Looks like inheritance-based assembly } object MyCar extends Car with DieselEngine
  • 21.
  • 22.
    ● Self-types areused with traits ● Explicitly declare the type of the value this ● Specify the requirements on any concrete class or instance the trait is mixed into. ● Declare a dependency of the trait on another type: “In order to use me you have to be one of those”
  • 23.
    So, tell memore about self-types
  • 24.
    No need tocall the self-type "this" You can use this-aliasing to give it a different name:
  • 25.
    trait Car { engine:Engine => def drive() { engine.start() println("Vroom vroom") } } Useful for nested classes or traits, where accessing a particular this would otherwise be difficult
  • 26.
    Self-types don’t automaticallyinherit: trait HondaCar extends Car // error: self-type HondaCar does not conform to Car's selftype Car with Engine Need to repeat the self-type in subtypes: trait HondaCar extends Car { this: Engine => // ... }
  • 27.
    A self-type canrequire multiple types: trait Car { this: Engine with FuelTank with GearBox => // ... } Used when the trait has multiple dependencies
  • 28.
    The self-type canbe a structural type: trait Car { this: { def start: Unit def stop: Unit } => // ... } Allows for safe mixins with duck-typing. (Useful when interacting with external dependencies)
  • 29.
    So all isgood with self-types?
  • 30.
    Hmm, well no: valmyCar = new Car extends DieselEngine {} myCar is still a Car and an Engine :(
  • 31.
    So here's aquick fix: val myCar: Car = new Car extends DieselEngine {} … but that's cheating (a bit)! And it doesn't work for singletons: object MyCar extends Car with DieselEngine
  • 32.
    What we needis a way to wire up and assemble our components without changing their identity
  • 33.
  • 35.
    Ok, so here'sthe recipe:
  • 36.
    For each componentin our system, supply a Component trait, that declares: ● Any dependent components, using self-types ● A trait describing the component's interface ● An abstract val that will be instantiated with an instance of the component ● Optionally, implementations of the component interface
  • 37.
    trait EngineComponent { traitEngine { private var running = false def start(): Unit = { /* as before */ } def stop(): Unit = {/* as before */ } def isRunning: Boolean = running def fuelType: FuelType } protected val engine : Engine protected class DieselEngine extends Engine { override val fuelType = FuelType.Diesel } }
  • 38.
    trait CarComponent { this:EngineComponent => // gives access to engine trait Car { def drive(): Unit def park(): Unit } protected val car: Car protected class HondaCar extends Car { override def drive() { engine.start() println("Vroom vroom") } override def park() { … } } }
  • 39.
    Great, now let'stie it all together: (remember a Car has a couple more components beside an Engine)
  • 40.
    object App extendsCarComponent with EngineComponent with FuelTankComponent with GearboxComponent { override protected val engine = new DieselEngine() override protected val fuelTank = new FuelTank(capacity = 60) override protected val gearBox = new FiveGearBox() override val car = new HondaCar() } MyApp.car.drive() MyApp.car.park()
  • 41.
    If we wantto write a CarTest, we can provide mock instances for the components we're not testing:
  • 42.
    val testCar =new CarComponent with EngineComponent with FuelTankComponent with GearboxComponent { override protected val engine = mock[Engine] // mock engine override protected val fuelTank = mock[FuelTank] // mock tank override protected val gearBox = new FiveGearBox() // an actual gearbox override val car = new HondaCar() }.car
  • 43.
  • 44.
    The Cake Pattern +Environment specific assembly of components + Compile-time checked, typesafe + Everything is immutable + No external DI descriptor - Can become hard to read and understand - May be difficult to configure components - No control over initialization order - Self-types prone to fragile base class problem
  • 45.
    Remember this: trait Car{ engine: Engine => def drive() { /* start engine */ } def park() { /* stop engine */ } } object MyCar extends Car with DieselEngine How did they do it? Let's decompile MyCar.class
  • 46.
    > javap com.example.MyCar Compiledfrom "Car.scala" public final class com.example.MyCar extends java.lang.Object{ public static void park(); public static void drive(); public static boolean isRunning(); public static void stop(); public static void start(); /* … */ } All functions from Car and Engine have been "lifted" into the top-level class!
  • 47.
    Imagine Car andEngine are part of a library that I'm using to construct MyCar. Any change to library-private interactions between these traits are not reflected in MyCar. class
  • 48.
  • 49.
    Ergo: Be very carefulexposing self-types as part of a library
  • 50.
  • 51.
    Sources: ● ● ● ● ● ● ● ● ● M. Odersky, L.Spoon, B. Venners: Programming in Scala, 2nd Edition C. S. Horstmann: Scala for the Impatient M. Odersky: Scalable Component Abstractions http://lampwww.epfl.ch/~odersky/papers/ScalableComponent.pdf J. Bonér: Real-World Scala: Dependency Injection (DI) http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di A Tour of Scala: Explicitly Typed Self References http://www.scala-lang.org/old/node/124 Cake pattern in depth http://www.cakesolutions.net/teamblogs/2011/12/19/cake-pattern-in-depth Dependency Injection In Scala using Self Type Annotations http://blog.knoldus.com/2013/01/21/dependency-injection-in-scala-using-self-type-annotations Cake Pattern in Scala / Self type annotations / Explicitly Typed Self References - explained https://coderwall.com/p/t_rapw DI in Scala: Cake Pattern pros & cons http://www.warski.org/blog/2011/04/di-in-scala-cake-pattern-pros-cons