scala/ScalaBook/chapter-12/src/main/scala/scalabook/ep/dc/sub/sub.scala

package scalabook.ep.dc.sub

/**
 * Definitions for a Data-Centric approach with subclassing.
 *
 * @author Christos KK Loverdos
 */

// We add a new operation: string representation of data
// By extending tha base data trait.
// This means we must add the new operation to all concrete
// data implementations
trait ReprD extends BaseD {
  def repr: String
}

// Extension (via subclassing) of literal numbers that supports
// string representation
class ReprNumD(value: Int) extends NumD(value) with ReprD {
    def repr = value.toString
}

// Extension (via subclassing) of added data that supports
// string representation
class ReprPlusD(a: ReprD, b: ReprD) extends PlusD(a, b) with ReprD {
  def repr = a.repr + " + " + b.repr
}

object AutoRepr {
  // But in {@link ReprNumD} the type of the constructor arguments
  // are ReprD and not BaseD, so we cannot reuse pre-existing BaseD
  // instances...
  // One way out of this is to create a few implicit conversions...
  implicit def NumD2ReprNumD(data: NumD) = new ReprNumD(data.eval)
}

// Another line of attack, apart from the above implicit, is to provide
// auxiliary constructors...
class ReprNumD2(value: Int) extends NumD(value) with ReprD {
  def this(numd: NumD) = this(numd.eval)
    def repr = value.toString
}

// Yet another slight modification in the above alternative to ReprNumD,
// is to have the auxiliary constructor take any BaseD as a parameter
// and not just NumD
class ReprNumD3(value: Int) extends NumD(value) with ReprD {
  def this(data: BaseD) = this(data.eval)
    def repr = value.toString
}