Tour of Scala

Class Composition with Mixins

Language

Mixins are traits which are used to compose a class.

abstract class A { val message: String } class B extends A { val message = "I'm an instance of class B" } trait C extends A { def loudMessage = message.toUpperCase() } class D extends B with C val d = new D println(d.message) // I'm an instance of class B println(d.loudMessage) // I'M AN INSTANCE OF CLASS B 

Class D has a superclass B and a mixin C. Classes can only have one superclass but many mixins (using the keywords extends and with respectively). The mixins and the superclass may have the same supertype.

abstract class A: val message: String class B extends A: val message = "I'm an instance of class B" trait C extends A: def loudMessage = message.toUpperCase() class D extends B, C val d = D() println(d.message) // I'm an instance of class B println(d.loudMessage) // I'M AN INSTANCE OF CLASS B 

Class D has a superclass B and a mixin C. Classes can only have one superclass but many mixins (using the keyword extends and the separator , respectively). The mixins and the superclass may have the same supertype.

Now let’s look at a more interesting example starting with an abstract class:

abstract class AbsIterator { type T def hasNext: Boolean def next(): T } 
abstract class AbsIterator: type T def hasNext: Boolean def next(): T 

The class has an abstract type T and the standard iterator methods.

Next, we’ll implement a concrete class (all abstract members T, hasNext, and next have implementations):

class StringIterator(s: String) extends AbsIterator { type T = Char private var i = 0 def hasNext = i < s.length def next() = { val ch = s charAt i i += 1 ch } } 
class StringIterator(s: String) extends AbsIterator: type T = Char private var i = 0 def hasNext = i < s.length def next() = val ch = s charAt i i += 1 ch 

StringIterator takes a String and can be used to iterate over the String (e.g. to see if a String contains a certain character).

Now let’s create a trait which also extends AbsIterator.

trait RichIterator extends AbsIterator { def foreach(f: T => Unit): Unit = while (hasNext) f(next()) } 

This trait implements foreach by continually calling the provided function f: T => Unit on the next element (next()) as long as there are further elements (while (hasNext)). Because RichIterator is a trait, it doesn’t need to implement the abstract members of AbsIterator.

trait RichIterator extends AbsIterator: def foreach(f: T => Unit): Unit = while hasNext do f(next()) 

This trait implements foreach by continually calling the provided function f: T => Unit on the next element (next()) as long as there are further elements (while hasNext). Because RichIterator is a trait, it doesn’t need to implement the abstract members of AbsIterator.

We would like to combine the functionality of StringIterator and RichIterator into a single class.

class RichStringIter extends StringIterator("Scala") with RichIterator val richStringIter = new RichStringIter richStringIter.foreach(println) 
class RichStringIter extends StringIterator("Scala"), RichIterator val richStringIter = RichStringIter() richStringIter.foreach(println) 

The new class RichStringIter has StringIterator as a superclass and RichIterator as a mixin.

With single inheritance we would not be able to achieve this level of flexibility.

Contributors to this page: