package expAbstractData /** A base class consisting of * - a root trait (i.e. abstract class) `Exp' with an `eval' function * - an abstract type `exp' bounded by `Exp' * - a concrete instance class `Num' of `Exp' for numeric literals */ trait Base { type exp <: Exp trait Exp { def eval: int } trait Num extends Exp { val value: int def eval = value } } object testBase extends Base with Application { type exp = Exp val term = new Num { val value = 1 } System.out.println(term.eval) } /** Data extension 1: An extension of `Base' with `Plus' expressions */ trait BasePlus extends Base { trait Plus extends Exp { val left: exp val right: exp def eval = left.eval + right.eval } } /** Data extension 2: An extension of `Base' with negation expressions */ trait BaseNeg extends Base { trait Neg extends Exp { val operand: exp def eval = - operand.eval } } /** Combining the plus and negation data extensions */ trait BasePlusNeg extends BasePlus with BaseNeg /** A test object for the combination class. * It ``ties the knot'' by equating the abstract type `exp' with * the root class `Exp'. */ object testBasePlusNeg extends BasePlusNeg with Application { type exp = Exp val term = new Neg { val operand = new Plus { val left = new Num { val value = 1 } val right = new Num { val value = 2 } } } System.out.println(term.eval) } /////////////////////////////////////////////////////////////////// /** Operation extension 1: An extension of `Base' with a `show' function. * This class needs * - a new root class `Exp' which adds a `show' method to `super.Exp', * the old root class in `Base', * - a rebinding of the abstract type `exp' to be a subtype of the new root class, * - a new class for numeric literals which adds a `show' method to `super.Num'. */ trait Show extends Base { type exp <: Exp trait Exp extends super.Exp { def show: String } trait Num extends super.Num with Exp { def show = value.toString() } } /** Combining operation extension 1 with the data extensions: * - we only need to implement `show' for the two extension classes * `Plus` and `Neg`. */ trait ShowPlusNeg extends BasePlusNeg with Show { trait Plus extends super.Plus with Exp { def show = left.show + "+" + right.show } trait Neg extends super.Neg with Exp { def show = "-(" + operand.show + ")" } } /** Testing the resulting combination. */ object testShowPlusNeg extends ShowPlusNeg with Application { type exp = Exp val term = new Neg { val operand = new Plus { val left = new Num { val value = 1 } val right = new Num { val value = 2 } } } System.out.println(term.show + " = " + term.eval) } /* object error { val t1 = new testShowPlusNeg.Num { val value = 1 } val t2 = new testDblePlusNeg.Neg { val value = t1 } val t3 = t1.dble } */ //////////////////////////////////////////////////////////////////////// /** Operation extension 2: An extension of `BasePlusNeg' with a `dble' method, * which returns an expression tree representing the original tree times two. * - The extension class redefines all data classes of `BasePlusNeg', adding * a `dble' method to each. * - Note that we need factory methods to build expression trees of the right * type (either DblePlusNeg.Exp, or an extension thereof). */ trait DblePlusNeg extends BasePlusNeg { type exp <: Exp trait Exp extends super.Exp { def dble: exp } def Num(v: int): exp def Plus(l: exp, r: exp): exp def Neg(t: exp): exp trait Num extends super.Num with Exp { def dble = Num(value * 2) } trait Plus extends super.Plus with Exp { def dble = Plus(left.dble, right.dble) } trait Neg extends super.Neg with Exp { def dble = Neg(operand.dble) } } /** Testing the resulting combination */ object testDblePlusNeg extends DblePlusNeg with Application { type exp = Exp def Num(v: int): exp = new Num { val value = v } def Plus(l: exp, r: exp): exp = new Plus { val left = l; val right = r} def Neg(t: exp): exp = new Neg { val operand = t } val term = Neg(Plus(Num(1), Num(2))) System.out.println(term.dble.eval) } /** Combining both operation extensions: * - This is done by a composing corresponding data classes of each extension. */ trait ShowDblePlusNeg extends ShowPlusNeg with DblePlusNeg { type exp <: Exp trait Exp extends super[ShowPlusNeg].Exp with super[DblePlusNeg].Exp trait Num extends super[ShowPlusNeg].Num with super[DblePlusNeg].Num with Exp trait Plus extends super[ShowPlusNeg].Plus with super[DblePlusNeg].Plus with Exp trait Neg extends super[ShowPlusNeg].Neg with super[DblePlusNeg].Neg with Exp } /** Testing the resulting combination */ object testShowDblePlusNeg extends ShowDblePlusNeg with Application { type exp = Exp def Num(v: int): exp = new Num { val value = v } def Plus(l: exp, r: exp): exp = new Plus { val left = l; val right = r } def Neg(t: exp): exp = new Neg { val operand = t } val term = Neg(Plus(Num(1), Num(2))) System.out.println("2 * (" + term.show + ") = " + term.dble.eval) } ///////////////////////////////////////////////////////////// /** Binary methods */ trait Equals extends Base { type exp <: Exp trait Exp extends super.Exp { def eql(other: exp): boolean def isNum(v: int) = false } trait Num extends super.Num with Exp { def eql(other: exp): boolean = other.isNum(value) override def isNum(v: int) = v == value } } trait EqualsPlusNeg extends BasePlusNeg with Equals { type exp <: Exp trait Exp extends super[BasePlusNeg].Exp with super[Equals].Exp { def isPlus(l: exp, r: exp): boolean = false def isNeg(t: exp): boolean = false } trait Num extends super[Equals].Num with Exp trait Plus extends Exp with super.Plus { def eql(other: exp): boolean = other.isPlus(left, right) override def isPlus(l: exp, r: exp) = (left eql l) && (right eql r) } trait Neg extends Exp with super.Neg { def eql(other: exp): boolean = other.isNeg(operand) override def isNeg(t: exp) = operand eql t } } /** Testing the resulting combination */ object testEqualsPlusNeg extends EqualsPlusNeg with Application { type exp = Exp val term = new Neg { val operand = new Plus { val left = new Num { val value = 1 } val right = new Num { val value = 2 } } } System.out.println(term eql term) System.out.println(term eql new Num { val value = 1 }) } //////////////////////////////////////////////////////////////////// trait EqualsShowPlusNeg extends EqualsPlusNeg with ShowPlusNeg { type exp <: Exp trait Exp extends super[EqualsPlusNeg].Exp with super[ShowPlusNeg].Exp trait Num extends super[EqualsPlusNeg].Num with super[ShowPlusNeg].Num with Exp trait Plus extends super[EqualsPlusNeg].Plus with super[ShowPlusNeg].Plus with Exp trait Neg extends super[EqualsPlusNeg].Neg with super[ShowPlusNeg].Neg with Exp } /** Testing the resulting combination */ object testEqualsShowPlusNeg extends EqualsPlusNeg with Application { type exp = Exp val term = new Neg { val operand = new Plus { val left = new Num { val value = 1 } val right = new Num { val value = 2 } } } val term2 = new Neg { val operand = new Num { val value = 1 } } System.out.println(term eql term) System.out.println(term eql term2) }