Skip to content

Commit 1692b5f

Browse files
authored
Merge pull request #713 from travissarles/traits
Rewrote traits tour
2 parents 7ac992c + 12bb8c5 commit 1692b5f

File tree

1 file changed

+60
-32
lines changed

1 file changed

+60
-32
lines changed

tutorials/tour/_posts/2017-02-13-traits.md

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,74 @@ categories: tour
99
num: 5
1010
next-page: mixin-class-composition
1111
previous-page: classes
12+
assumed-knowledge: expressions, classes, generics, objects, companion-objects
1213
---
1314

14-
Similar to interfaces in Java, traits are used to define object types by specifying the signature of the supported methods. Like in Java 8, Scala allows traits to be partially implemented; i.e. it is possible to define default implementations for some methods. In contrast to classes, traits may not have constructor parameters.
15-
Here is an example:
16-
15+
Traits are used to share interfaces and fields between classes. They are similar to Java 8's interfaces. Classes and objects can extend traits but traits cannot be instantiated and therefore have no parameters.
16+
17+
## Defining a trait
18+
A minimal trait is simply the keyword `trait` and an identifier:
19+
20+
```tut
21+
trait HairColor
22+
```
23+
24+
Traits become especially useful as generic types and with abstract methods.
1725
```tut
18-
trait Similarity {
19-
def isSimilar(x: Any): Boolean
20-
def isNotSimilar(x: Any): Boolean = !isSimilar(x)
26+
trait Iterator[A] {
27+
def hasNext: Boolean
28+
def next(): A
2129
}
2230
```
23-
24-
This trait consists of two methods `isSimilar` and `isNotSimilar`. While `isSimilar` does not provide a concrete method implementation (it is abstract in the terminology of Java), method `isNotSimilar` defines a concrete implementation. Consequently, classes that integrate this trait only have to provide a concrete implementation for `isSimilar`. The behavior for `isNotSimilar` gets inherited directly from the trait. Traits are typically integrated into a [class](classes.html) (or other traits) with a [mixin class composition](mixin-class-composition.html):
25-
31+
32+
Extending the `trait Iterator[A]` requires a type `A` and implementations of the methods `hasNext` and `next`.
33+
34+
## Using traits
35+
Use the `extends` keyword to extend a trait. Then implement any abstract members of the trait using the `override` keyword:
2636
```tut
27-
class Point(xc: Int, yc: Int) extends Similarity {
28-
var x: Int = xc
29-
var y: Int = yc
30-
def isSimilar(obj: Any) =
31-
obj.isInstanceOf[Point] &&
32-
obj.asInstanceOf[Point].x == x
37+
trait Iterator[A] {
38+
def hasNext: Boolean
39+
def next(): A
3340
}
34-
object TraitsTest extends App {
35-
val p1 = new Point(2, 3)
36-
val p2 = new Point(2, 4)
37-
val p3 = new Point(3, 3)
38-
val p4 = new Point(2, 3)
39-
println(p1.isSimilar(p2))
40-
println(p1.isSimilar(p3))
41-
// Point's isNotSimilar is defined in Similarity
42-
println(p1.isNotSimilar(2))
43-
println(p1.isNotSimilar(p4))
41+
42+
43+
class IntIterator(to: Int) extends Iterator[Int] {
44+
private var current = 0
45+
override def hasNext: Boolean = current < to
46+
override def next(): Int = {
47+
if (hasNext) {
48+
val t = current
49+
current += 1
50+
t
51+
} else 0
52+
}
4453
}
45-
```
46-
47-
Here is the output of the program:
4854
55+
56+
val iterator = new IntIterator(10)
57+
iterator.next() // prints 0
58+
iterator.next() // prints 1
4959
```
50-
true
51-
false
52-
true
53-
false
60+
This `IntIterator` class takes a parameter `to` as an upper bound. It `extends Iterator[Int]` which means that the `next` method must return an Int.
61+
62+
## Subtyping
63+
Subtypes of traits can be used where a the trait is required.
64+
```tut
65+
import scala.collection.mutable.ArrayBuffer
66+
67+
trait Pet {
68+
val name: String
69+
}
70+
71+
class Cat(val name: String) extends Pet
72+
class Dog(val name: String) extends Pet
73+
74+
val dog = new Dog("Harry")
75+
val cat = new Cat("Sally")
76+
77+
val animals = ArrayBuffer.empty[Pet]
78+
animals.append(dog)
79+
animals.append(cat)
80+
animals.foreach(pet => println(pet.name)) // Prints Harry Sally
5481
```
82+
The `trait Pet` has an abstract field `name` which gets implemented by Cat and Dog in their constructors. On the last line, we call `pet.name` which must be implemented in any subtype of the trait `Pet`.

0 commit comments

Comments
 (0)