scala/epDa1.scala

// Base data
trait BaseD {
    def eval: Int
}

class IntD(val value: Int) extends BaseD {
    def eval() = value

}

// data extension: PlusD
class PlusD(val l: BaseD, val r: BaseD) extends BaseD {
    def eval() = l.eval + r.eval
}

// operation extension

trait ReprD extends BaseD {
    def repr: String
}

class IntR(value: Int) extends IntD(value) with ReprD {
    def repr() = value.toString
}

class PlusR(l: BaseD, r: BaseD) extends PlusD(l, r) with ReprD {
    def repr() =  "(" + l.asInstanceOf[ReprD].repr + '+' + r.asInstanceOf[ReprD].repr + ')'
}

object ReprD {
    implicit def I2R(i: BaseD) = i.asInstanceOf[ReprD]
    implicit def I2R(i: PlusD) = i.asInstanceOf[PlusR]
}
class PlusRA(l: BaseD, r: BaseD) extends PlusD(l, r) with ReprD {
    def repr() =  "(" + ReprD.I2R(l).repr + '+' + ReprD.I2R(r).repr + ')'
}


/*
val i1 = new IntD(11)
val i2 = new IntD(22)
val p3 = new PlusD(i1, i2)
val p4 = new PlusD(p3, new PlusD(new IntD(4), new IntD(44)))
val i5 = new IntR(55)
val i6 = new IntR(66)
val p7 = new PlusR(i5, i6)
val p8 = new PlusR(i5, i2)
val a9 = new PlusRA(i5, i6)
val aa = new PlusRA(i5, i2)
*/

/*
// data extension: PlusD
class PlusD(val l: BaseD, val r: BaseD) extends BaseD {
    def eval() = l.eval + r.eval
}

    def allT = (this, eval, repr)
    def allS = this.toString + " =eval=> " + eval + " =repr=> " + repr

val a = new NumD(12) 
(a, a eval, a repr)
a.allT
a.allS
new NumPlus(a, new NumD(98)) allS
new NumPlus(new NumPlus(new NumD(12), new NumD(34)), new NumD(98)) allS

// Base operation.
trait BaseOp {def computeNumD(data: NumD)}

// 1st concrete operation: evaluate the data
class EvalOp extends BaseOp {
  var result: Option[Int] = _
  def apply(data: BaseD) = {data.perform(this); result.get }
  def computeNumD(data: NumD) {this.result = Some(data.value) }
}

// utility object for on-the-fly evaluations
object eval {def apply(data: BaseD) = new EvalOp()(data)}
*/