scala/ScalaBook/chapter-12/src/main/scala/scalabook/ep/ocgenselfp/base.scala
package scalabook.ep.ocgenselfp
/**
* Definitions for an Operation-Centric approach with generics
* with Torgersen's trick to introduce an extra self parameter.
*
* These are te base definitions. See sub/sub.scala for data extensions.
*
* @author Christos KK Loverdos
*/
trait BaseD[V <: BaseOp] {
def perform(op: V)
}
trait BaseOp {
// Note the extra self parameter that provides the correct V type
// for data to call perform --> see EvalOp::apply
def computeNumD[V <: BaseOp](data: NumD[V], self: V)
}
class NumD[V <: BaseOp](val value: Int) extends BaseD[V] {
def perform(op: V) {
op.computeNumD(this, op)
}
}
class EvalOp extends BaseOp {
var result: Option[Int] = None
def apply[V <: BaseOp](data: BaseD[V], self: V) = {
data.perform(self) // self here has the correct value (this doesnot!)
result.get
}
def computeNumD[V <: BaseOp](data: NumD[V], self: V) {
this.result = Some(data.value)
}
}
class ReprOp extends BaseOp {
var result: Option[String] = _
def apply[V <: BaseOp](data: BaseD[V], self: V) = {
data.perform(self)
result.get
}
def computeNumD[V <: BaseOp](data: NumD[V], self: V) {
this.result = Some(data.value.toString)
}
}
object eval {
def apply[V <: BaseOp](data: BaseD[V], self: V) = new EvalOp()(data, self)
}
object repr {
def apply[V <: BaseOp](data: BaseD[V], self: V) = new ReprOp()(data, self)
}