diff --git a/tutorials/tour/_posts/2017-02-13-abstract-types.md b/tutorials/tour/_posts/2017-02-13-abstract-types.md index a3d63ab744..2eecb7fde6 100644 --- a/tutorials/tour/_posts/2017-02-13-abstract-types.md +++ b/tutorials/tour/_posts/2017-02-13-abstract-types.md @@ -7,7 +7,7 @@ disqus: true tutorial: scala-tour categories: tour num: 23 -next-page: compound-types +next-page: self-types previous-page: inner-classes prerequisite-knowledge: variance, upper-type-bound --- diff --git a/tutorials/tour/_posts/2017-02-13-compound-types.md b/tutorials/tour/_posts/2017-02-13-compound-types.md deleted file mode 100644 index d7b44ce37f..0000000000 --- a/tutorials/tour/_posts/2017-02-13-compound-types.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -layout: tutorial -title: Compound Types - -disqus: true - -tutorial: scala-tour -categories: tour -num: 24 -next-page: explicitly-typed-self-references -previous-page: abstract-types ---- - -Sometimes it is necessary to express that the type of an object is a subtype of several other types. In Scala this can be expressed with the help of *compound types*, which are intersections of object types. - -Suppose we have two traits `Cloneable` and `Resetable`: - -```tut -trait Cloneable extends java.lang.Cloneable { - override def clone(): Cloneable = { - super.clone().asInstanceOf[Cloneable] - } -} -trait Resetable { - def reset: Unit -} -``` - -Now suppose we want to write a function `cloneAndReset` which takes an object, clones it and resets the original object: - -``` -def cloneAndReset(obj: ?): Cloneable = { - val cloned = obj.clone() - obj.reset - cloned -} -``` - -The question arises what the type of the parameter `obj` is. If it's `Cloneable` then the object can be `clone`d, but not `reset`; if it's `Resetable` we can `reset` it, but there is no `clone` operation. To avoid type casts in such a situation, we can specify the type of `obj` to be both `Cloneable` and `Resetable`. This compound type is written like this in Scala: `Cloneable with Resetable`. - -Here's the updated function: - -``` -def cloneAndReset(obj: Cloneable with Resetable): Cloneable = { - //... -} -``` - -Compound types can consist of several object types and they may have a single refinement which can be used to narrow the signature of existing object members. -The general form is: `A with B with C ... { refinement }` - -An example for the use of refinements is given on the page about [abstract types](abstract-types.html). diff --git a/tutorials/tour/_posts/2017-02-13-self-types.md b/tutorials/tour/_posts/2017-02-13-self-types.md index 242d205997..1f39004803 100644 --- a/tutorials/tour/_posts/2017-02-13-self-types.md +++ b/tutorials/tour/_posts/2017-02-13-self-types.md @@ -8,7 +8,7 @@ tutorial: scala-tour categories: tour num: 25 next-page: implicit-parameters -previous-page: compound-types +previous-page: abstract-types prerequisite-knowledge: nested-classes, mixin-class-composition --- Self-types are a way to declare that a trait must be mixed into another trait, even though it doesn't directly extend it. That makes the members of the dependency available without imports. diff --git a/tutorials/tour/_posts/2017-02-13-traits.md b/tutorials/tour/_posts/2017-02-13-traits.md index 485bfee669..4398a95071 100644 --- a/tutorials/tour/_posts/2017-02-13-traits.md +++ b/tutorials/tour/_posts/2017-02-13-traits.md @@ -22,6 +22,7 @@ trait HairColor ``` Traits become especially useful as generic types and with abstract methods. + ```tut trait Iterator[A] { def hasNext: Boolean @@ -33,6 +34,7 @@ Extending the `trait Iterator[A]` requires a type `A` and implementations of the ## Using traits Use the `extends` keyword to extend a trait. Then implement any abstract members of the trait using the `override` keyword: + ```tut trait Iterator[A] { def hasNext: Boolean @@ -56,11 +58,13 @@ class IntIterator(to: Int) extends Iterator[Int] { val iterator = new IntIterator(10) iterator.next() // prints 0 iterator.next() // prints 1 + ``` 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. ## Subtyping Subtypes of traits can be used where a the trait is required. + ```tut import scala.collection.mutable.ArrayBuffer @@ -79,4 +83,36 @@ animals.append(dog) animals.append(cat) animals.foreach(pet => println(pet.name)) // Prints Harry Sally ``` + 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`. + +## Multiple Parameter Types + +Sometimes it is necessary to have parameter which has multiple supertypes. In Scala you can use the `with` keyword to express the intersection of multiple traits. + +Suppose we have two traits `Cloneable` and `Resetable`: + +```tut +trait Cloneable extends java.lang.Cloneable { + override def clone(): Cloneable = { + super.clone().asInstanceOf[Cloneable] + } +} +trait Resetable { + def reset: Unit +} +``` + +Now suppose we want to write a function `cloneAndReset` which takes an object, clones it and resets the original object. We use the keyword `with` to specify that the object must be a subtype of both types. + +``` +def cloneAndReset(obj: Cloneable with Resetable): Cloneable = { + val cloned = obj.clone() + obj.reset + cloned +} +``` + +Because the type of `obj` is `Cloneable with Resetable`, we know the object has both a `clone` and a `reset` method. + +Compound types can consist of several object types. The general form is: `A with B with C ...`.