Code Examples for

Programming in Scala

Return to chapter index

12 Traits

Sample run of chapter's interpreter examples

12.1 How traits work


// In file traits/Philosophical.scala trait Philosophical { def philosophize() { println("I consume memory, therefore I am!") } }
class Frog extends Philosophical { override def toString = "green" }
scala> val frog = new Frog frog: Frog = green scala> frog.philosophize() I consume memory, therefore I am!
scala> val phil: Philosophical = frog phil: Philosophical = green scala> phil.philosophize() I consume memory, therefore I am!
// In file traits/Ex1.scala class Animal class Frog extends Animal with Philosophical { override def toString = "green" }
// In file traits/Frog.scala class Animal trait HasLegs class Frog extends Animal with Philosophical with HasLegs { override def toString = "green" }
// In file traits/Ex2.scala class Animal class Frog extends Animal with Philosophical { override def toString = "green" override def philosophize() { println("It ain't easy being "+ toString +"!") } }
scala> val phrog: Philosophical = new Frog phrog: Philosophical = green scala> phrog.philosophize() It ain't easy being green!
// In file traits/Ex2.scala class Point(x: Int, y: Int)
trait NoPoint(x: Int, y: Int) // Does not compile

12.2 Thin versus rich interfaces


// In file traits/Ex2.scala trait CharSequence { def charAt(index: Int): Char def length: Int def subSequence(start: Int, end: Int): CharSequence def toString(): String }

12.3 Example: Rectangular objects


// In file traits/Point.scala class Point(val x: Int, val y: Int) class Rectangle(val topLeft: Point, val bottomRight: Point) { def left = topLeft.x def right = bottomRight.x def width = right - left // and many more geometric methods... }
abstract class Component { def topLeft: Point def bottomRight: Point def left = topLeft.x def right = bottomRight.x def width = right - left // and many more geometric methods... }
// In file traits/Rectangular.scala trait Rectangular { def topLeft: Point def bottomRight: Point def left = topLeft.x def right = bottomRight.x def width = right - left // and many more geometric methods... }
abstract class Component extends Rectangular { // other methods... }
// In file traits/Rectangle.scala class Rectangle(val topLeft: Point, val bottomRight: Point) extends Rectangular { // other methods... }
scala> val rect = new Rectangle(new Point(1, 1), | new Point(10, 10)) rect: Rectangle = Rectangle@3536fd scala> rect.left res2: Int = 1 scala> rect.right res3: Int = 10 scala> rect.width res4: Int = 9

12.4 The Ordered trait


class Rational(n: Int, d: Int) { // ... def < (that: Rational) = this.numer * that.denom > that.numer * this.denom def > (that: Rational) = that < this def <= (that: Rational) = (this < that) || (this == that) def >= (that: Rational) = (this > that) || (this == that) }
// In file traits/Rational.scala class Rational(n: Int, d: Int) extends Ordered[Rational] { // ... def compare(that: Rational) = (this.numer * that.denom) - (that.numer * this.denom) }
scala> val half = new Rational(1, 2) half: Rational = 1/2 scala> val third = new Rational(1, 3) third: Rational = 1/3 scala> half < third res5: Boolean = false scala> half > third res6: Boolean = true
// In file traits/Ex2.scala trait Ordered[T] { def compare(that: T): Int def <(that: T): Boolean = (this compare that) < 0 def >(that: T): Boolean = (this compare that) > 0 def <=(that: T): Boolean = (this compare that) <= 0 def >=(that: T): Boolean = (this compare that) >= 0 }

12.5 Traits as stackable modifications


// In file traits/IntQueue.scala abstract class IntQueue { def get(): Int def put(x: Int) }
// In file traits/Ex2.scala import scala.collection.mutable.ArrayBuffer class BasicIntQueue extends IntQueue { private val buf = new ArrayBuffer[Int] def get() = buf.remove(0) def put(x: Int) { buf += x } }
scala> val queue = new BasicIntQueue queue: BasicIntQueue = BasicIntQueue@24655f scala> queue.put(10) scala> queue.put(20) scala> queue.get() res9: Int = 10 scala> queue.get() res10: Int = 20
// In file traits/Ex2.scala trait Doubling extends IntQueue { abstract override def put(x: Int) { super.put(2 * x) } }
scala> class MyQueue extends BasicIntQueue with Doubling defined class MyQueue scala> val queue = new MyQueue queue: MyQueue = MyQueue@91f017 scala> queue.put(10) scala> queue.get() res12: Int = 20
scala> val queue = new BasicIntQueue with Doubling queue: BasicIntQueue with Doubling = $anon$1@5fa12d scala> queue.put(10) scala> queue.get() res14: Int = 20
// In file traits/Incrementing.scala trait Incrementing extends IntQueue { abstract override def put(x: Int) { super.put(x + 1) } } trait Filtering extends IntQueue { abstract override def put(x: Int) { if (x >= 0) super.put(x) } }
scala> val queue = (new BasicIntQueue | with Incrementing with Filtering) queue: BasicIntQueue with Incrementing with Filtering... scala> queue.put(-1); queue.put(0); queue.put(1) scala> queue.get() res15: Int = 1 scala> queue.get() res16: Int = 2
scala> val queue = (new BasicIntQueue | with Filtering with Incrementing) queue: BasicIntQueue with Filtering with Incrementing... scala> queue.put(-1); queue.put(0); queue.put(1) scala> queue.get() res17: Int = 0 scala> queue.get() res18: Int = 1 scala> queue.get() res19: Int = 2

12.6 Why not multiple inheritance?


// In file traits/Ex2.scala // Multiple inheritance thought experiment val q = new BasicIntQueue with Incrementing with Doubling q.put(42) // which put would be called?
// Multiple inheritance thought experiment trait MyQueue extends BasicIntQueue with Incrementing with Doubling { def put(x: Int) { Incrementing.super.put(x) // (Not real Scala) Doubling.super.put(x) } }
// In file traits/Ex3.scala class Animal trait Furry extends Animal trait HasLegs extends Animal trait FourLegged extends HasLegs class Cat extends Animal with Furry with FourLegged

12.7 To trait, or not to trait?

12.8 Conclusion

For more information about Programming in Scala (the "Stairway Book"), please visit:

http://www.artima.com/shop/programming_in_scala

and:

http://booksites.artima.com/programming_in_scala

Copyright © 2007-2008 Artima, Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.