scala/epReg2.scala

// register operation by Operation subtypes

// traits
trait Op {
    def op : Op
    def evalOp(d: BaseD): Int
}
trait BaseD {
    def op: Op
}

// primary implementation IntD with eval
class IntD(val value: Int) extends BaseD {
    def op() = IntD.op
}
class IntEval extends Op {
    def evalOp(d: BaseD) = d.asInstanceOf[IntD].value
}
object IntD {
    var op: Op = new IntEval()
}
object eval {
    def apply(d: BaseD) = d.op.evalOp(d)
}

// data extension: PlusD
class PlusEval extends Op {
    def evalOp(d: BaseD) = eval(d.asInstanceOf[PlusD].l) + eval(d.asInstanceOf[PlusD].r)
}
class PlusD(val l: BaseD, val r: BaseD) extends BaseD {
    def op = PlusD.op
}
object PlusD {
    var op = new PlusEval
}

// operation extension
trait ReprOp extends Op {
    def reprOp(d: BaseD): String
}
class IntRepr extends IntEval with ReprOp {
    def reprOp(d: BaseD) =  d.asInstanceOf[IntD].value.toString
}
class PlusRepr extends PlusEval with ReprOp {
    def reprOp(d: BaseD) =  {val r = d.asInstanceOf[PlusD]; repr(r.l) + '+' + repr(r.r)}
}
object repr {
    def apply(d: BaseD) : String = 
    {     d.op match  
        {
            case r: ReprOp => r.reprOp(d)
            case r         => 
            {
                println("repr ini .....")
                IntD.op = new IntRepr()
                PlusD.op = new PlusRepr()
                repr(d)
            }
        }
    }
}

// show the elements
object EpReg1 { def show =
    {
        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)))
        var nm : String = "??"
        for (e <- List("i1", i1, "i2", i2, "p3", p3, "p4", p4)) {
            e match {
                case s: String => nm = s
                case d: BaseD => { println(nm + " " + d  + " eval " + eval(d))
                                   println(   "   " + d  + " eval " + eval(d) + " repr " + repr(d)) 
                }
            }
        }
    }
}