scala/ScalaBook/chapter-12/src/main/scala/scalabook/ep/family/oc/base.scala

package scalabook.ep.family.oc

/**
 * Family-based functional (operation-centric) decomposition.
 * 
 * @author Christos KK Loverdos
 */

trait BaseLang {
    type Operation <: BaseOp

    trait BaseD {
        def perform(op: Operation)
    }
    
    trait BaseOp {
        def computeNumD(data: NumD)
    }

    class NumD(val value: Int) extends BaseD {
        def perform(op: Operation) {
            op.computeNumD(this)
        }
    }

    class EvalOp extends BaseOp { this: Operation =>
        var result: Option[Int] = None

        def apply(data: BaseD) = {
            data.perform(this) // the self-type is needed for the call
            result.get
        }

        def computeNumD(data: NumD) {
            this.result = Some(data.value)
        }
    }

    def newEvalOp(): EvalOp with Operation

    object eval {
        def apply(data: BaseD) = newEvalOp()(data)
    }
}

object FixBaseLang extends BaseLang {
    type Operation = BaseOp

    def newEvalOp() = new EvalOp // Operation is fixed now
}