|
1 | 1 | --- |
2 | 2 | layout: tutorial |
3 | | -title: Mixin Class Composition |
| 3 | +title: Class Composition with Mixins |
4 | 4 |
|
5 | 5 | disqus: true |
6 | 6 |
|
7 | 7 | tutorial: scala-tour |
8 | 8 | categories: tour |
9 | 9 | num: 6 |
10 | | -next-page: anonymous-function-syntax |
| 10 | +next-page: higher-order-functions |
11 | 11 | previous-page: traits |
| 12 | +prerequisite-knowledge: inheritance, traits, abstract-classes, unified-types |
12 | 13 | --- |
| 14 | +Mixins are traits which are used to compose a class. |
| 15 | + |
| 16 | +```tut |
| 17 | +abstract class A { |
| 18 | + val message: String |
| 19 | +} |
| 20 | +class B extends A { |
| 21 | + val message = "I'm an instance of class B" |
| 22 | +} |
| 23 | +trait C extends A { |
| 24 | + def loudMessage = message.toUpperCase() |
| 25 | +} |
| 26 | +class D extends B with C |
| 27 | +
|
| 28 | +val d = new D |
| 29 | +d.message // I'm an instance of class B |
| 30 | +d.makeMessageLoud // I'M AN INSTANCE OF CLASS B |
| 31 | +``` |
| 32 | +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. |
| 33 | + |
| 34 | +Now let's look at a more interesting example starting with an abstract class: |
13 | 35 |
|
14 | | -As opposed to languages that only support _single inheritance_, Scala has a more general notion of class reuse. Scala makes it possible to reuse the _new member definitions of a class_ (i.e. the delta in relationship to the superclass) in the definition of a new class. This is expressed as a _mixin-class composition_. Consider the following abstraction for iterators. |
15 | | - |
16 | 36 | ```tut |
17 | 37 | abstract class AbsIterator { |
18 | 38 | type T |
19 | 39 | def hasNext: Boolean |
20 | 40 | def next: T |
21 | 41 | } |
22 | 42 | ``` |
23 | | - |
24 | | -Next, consider a mixin class which extends `AbsIterator` with a method `foreach` which applies a given function to every element returned by the iterator. To define a class that can be used as a mixin we use the keyword `trait`. |
25 | | - |
26 | | -```tut |
27 | | -trait RichIterator extends AbsIterator { |
28 | | - def foreach(f: T => Unit) { while (hasNext) f(next) } |
29 | | -} |
30 | | -``` |
31 | | - |
32 | | -Here is a concrete iterator class, which returns successive characters of a given string: |
33 | | - |
| 43 | +The class has an abstract type `T` and the standard iterator methods. |
| 44 | + |
| 45 | +Next, we'll implement a concrete class (all abstract members `T`, `hasNext`, and `next` have implementations): |
| 46 | + |
34 | 47 | ```tut |
35 | 48 | class StringIterator(s: String) extends AbsIterator { |
36 | 49 | type T = Char |
37 | 50 | private var i = 0 |
38 | | - def hasNext = i < s.length() |
39 | | - def next = { val ch = s charAt i; i += 1; ch } |
| 51 | + def hasNext = i < s.length |
| 52 | + def next = { |
| 53 | + val ch = s charAt i |
| 54 | + i += 1 |
| 55 | + ch |
| 56 | + } |
40 | 57 | } |
41 | 58 | ``` |
42 | | - |
43 | | -We would like to combine the functionality of `StringIterator` and `RichIterator` into a single class. With single inheritance and interfaces alone this is impossible, as both classes contain member implementations with code. Scala comes to help with its _mixin-class composition_. It allows the programmers to reuse the delta of a class definition, i.e., all new definitions that are not inherited. This mechanism makes it possible to combine `StringIterator` with `RichIterator`, as is done in the following test program which prints a column of all the characters of a given string. |
44 | | - |
| 59 | +`StringIterator` takes a `String` and can be used to iterate over the String (e.g. to see if a String contains a certain character). |
| 60 | + |
| 61 | +Now let's create a trait which also extends `AbsIterator`. |
| 62 | + |
45 | 63 | ```tut |
46 | | -object StringIteratorTest { |
47 | | - def main(args: Array[String]) { |
48 | | - class Iter extends StringIterator(args(0)) with RichIterator |
49 | | - val iter = new Iter |
50 | | - iter foreach println |
51 | | - } |
| 64 | +trait RichIterator extends AbsIterator { |
| 65 | + def foreach(f: T => Unit): Unit = while (hasNext) f(next) |
52 | 66 | } |
53 | 67 | ``` |
54 | | - |
55 | | -The `Iter` class in function `main` is constructed from a mixin composition of the parents `StringIterator` and `RichIterator` with the keyword `with`. The first parent is called the _superclass_ of `Iter`, whereas the second (and every other, if present) parent is called a _mixin_. |
| 68 | +Because `RichIterator` is a trait, it doesn't need to implement the abstract members of AbsIterator. |
| 69 | + |
| 70 | +We would like to combine the functionality of `StringIterator` and `RichIterator` into a single class. |
| 71 | + |
| 72 | +```tut |
| 73 | +object StringIteratorTest extends App { |
| 74 | + class Iter extends StringIterator(args(0)) with RichIterator |
| 75 | + val iter = new Iter |
| 76 | + iter foreach println |
| 77 | +} |
| 78 | +``` |
| 79 | +The new class `RichStringIter` has `StringIterator` as a superclass and `RichIterator` as a mixin. |
| 80 | + |
| 81 | +With single inheritance we would not be able to achieve this level of flexibility. |
0 commit comments