Friday, October 30, 2009

stackable modification with traits

This post just summarises how stackable modification(modifications made to classes by stacking components on top of a class) is done in scala using traits. In traits, super calls resolve dynamically. Following is the example from "Programming in Scala" by Martin Odersky.
abstract class IntQueue {
def get(): Int
def put(x: Int)
}
class BasicIntQueue extends IntQueue {
import scala.collection.mutable.ArrayBuffer
private val buf = new ArrayBuffer[Int]
def get() = buf.remove(0)
def put(x: Int) { buf += x }
}

//trait Doubling extends from IntQueue, this
//means, it can only be mixed with a class
//that also descends from IntQueue
trait Doubler extends IntQueue {

//calls like this are not allowed in normal classes
//here super call will resolve dynamically to the
//trait/class that is in left to this one while mixing
//and gives a concrete implementation to put
abstract override def put(x: Int) { super.put(2 * x) }
}

trait Increment extends IntQueue {
abstract override def put(x: Int) { super.put(x+1) }
}

class MyQ extends BasicIntQueue with Doubler

scala> val q = new MyQ
q: MyQ = MyQ@15bf0c5

//put in Doubler is executed(because its the rightmost component),
//super.put resolves in it
//resolves to put in BasicIntQueue as that is the next concret
//put available to it's left.
scala> q.put(10)

scala> q.put(20)

scala> q.get()
res60: Int = 20 //10 was doubled

scala> q.get()
res61: Int = 40 //20 was doubled

Notice MyQ does nothing else but the mixing only, it has no body. For this we can use the following shorthand code.
val q = new BasicIntQueue with Doubling

Let us check out one more case..
scala> val q = new BasicIntQueue with Incrementer with Doubler
q: BasicIntQueue with Incrementer with Doubler = $anon$1@4cfc65

//rightmost put is applied, which is the put in Doubler, super.put
//in Doubler resolves to put in Incrementer and same in Incrementer
//resolves to put in BasicIntQueue
scala> q.put(10)

scala> q.put(20)

scala> q.get()
res64: Int = 21 //21 = 10*2 + 1

scala> q.get()
res65: Int = 41 //41 = 20*2 + 1

No comments:

Post a Comment