Scala mixins具有相同的参数化类型

时间:2011-07-09 22:35:57

标签: design-patterns scala

我对scala非常陌生,并且正在进行调整scala特定模式的任务。 目标是分离消息处理和消息生成。存在表示消息处理的基本协变参数化类型。具体的实现可以通过常规mixin或混合基础协议来进行。

要求是:

  1. 尽可能扩展为simaple

  2. 防止愚蠢错误的类型安全

  3. 我已经提供了干净的示例代码(包含定义和使用):

    trait Protocol
    
    trait Handler [+proto <: Protocol] {
      def handle : PartialFunction[Protocol,Unit] 
      /* can not name the actual protocol type since handler for a subtype also fully supports handling supertype
    besides any message extends other subtype ot the supertype since the scala use matching with case classes
    and these algebraic type realization is seemed excluded from strait scala type system
      */
    }
    
    /*
    ==============
    using scenario
    ==============
    */
    
    trait SumMsg extends Protocol
    case class Sum(op : Int) extends SumMsg
    case class Sub(op : Int) extends SumMsg
    
    trait ProdMsg extends Protocol
    case class Mul(op : Int) extends ProdMsg
    case class Diff(op : Int) extends ProdMsg {
      require (0 != op, "Division by zero is not permited")
    }
    
    /* stackable traites */
    trait NullHandler {
      def handle : PartialFunction[Protocol,Unit] = { case _ => {} }
    }
    
    trait SumHandler extends Handler [SumMsg] with NullHandler{
      var store : Int
      abstract override def handle : PartialFunction[Protocol,Unit] = ({
    case Sum(op) => { this.store += op}
    case Sub(op) => { this.store -= op}
      }: PartialFunction[Protocol,Unit]) orElse super.handle
    }
    
    trait MulHandler extends Handler [ProdMsg] with NullHandler{
      var store : Int
      abstract override def handle : PartialFunction[Protocol,Unit] = ({
    case Mul(op) => {this.store *= op}
    case Diff(op) => {this.store /= op}
      }: PartialFunction[Protocol,Unit]) orElse super.handle
    }
    
    /* concrete classes */
    class SumAccum (var store: Int) extends SumHandler
    
    class MulAccum (var store: Int) extends MulHandler
    
    class ArithmAccum (var store: Int) extends SumHandler with MulHandler
    
    /* producers */
    class ProduceSums (val accum : Handler [SumMsg]) {
      var state : Boolean = true
      def touch() = if (this.state)
    {
      this.state = false
      this.accum.handle(Sum(2))
    } else {
      this.state = true
      this.accum.handle(Sub(1))
    }
    }
    
    class ProduceProds (val accum : Handler [ProdMsg]) {
      var state : Boolean = true
      def touch() = if (this.state)
    {
      this.state = false
      this.accum.handle(Mul(2))
    } else {
      this.state = true
      this.accum.handle(Diff(2))
    }
    }
    
    /* tying together via cake pattern */
    trait ProtocolComp {
      type Proto <: Protocol
    }
    
    trait ProducerComp { this: ProtocolComp =>
      type ProducerT <: {def touch()}
      def getProducer(accum : Handler[Proto]) : ProducerT
    }
    
    trait HandlerComp { this: ProtocolComp =>
      type HandlerT <: Handler[Proto]
      def getHandler(store:Int) : HandlerT
    }
    
    trait AppComp extends ProtocolComp with ProducerComp with HandlerComp {
      val initStore = 1
      def test() {
    val handler = getHandler(initStore)
    val producer = getProducer(handler)
    producer.touch()
      }
    }
    
    /* different examples of compositions */
    
    /* correct usage */
    
    object One extends AppComp{
      override type Proto = SumMsg
      override type ProducerT = ProduceSums
      override type HandlerT = SumAccum
      override def getProducer(accum : Handler[Proto]) = new ProduceSums(accum)
      override def getHandler(store : Int) = new SumAccum(store)
    }
    
    object Two extends AppComp{
      override type Proto = SumMsg
      override type ProducerT = ProduceSums
      override type HandlerT = ArithmAccum
      override def getProducer(accum : Handler[Proto]) = new ProduceSums(accum)
      override def getHandler(store : Int) = new ArithmAccum(store)
    }
    
    object Three extends AppComp{
      override type Proto = SumMsg with ProdMsg
      override type ProducerT = ProduceSums
      override type HandlerT = ArithmAccum
      override def getProducer(accum : Handler[Proto]) = new ProduceSums(accum)
      override def getHandler(store : Int) = new ArithmAccum(store)
    }
    
    /* incorrect usage
    static type checking protects from some kind of logic errors
    */
    
    object Four extends AppComp{
      override type Proto = SumMsg
      override type ProducerT = ProduceProds
      override type HandlerT = SumAccum
      override def getProducer(accum : Handler[Proto]) = new ProduceProds(accum)
      override def getHandler(store : Int) = new SumAccum(store)
    }
    

    最后一个示例输入不正确,并按预期出现错误:

    mixed.scala:140: error: type mismatch;
    found   : Handler[Four.Proto]
    required: Handler[ProdMsg]
      override def getProducer(accum : Handler[Proto]) = new ProduceProds(accum)
    

    我构建了一个灵活的系统,简单的组合和扩展,但尽可能使用scala的case类而不是alegraic类型

    我几乎实现了我的目标,但遇到了一个很大的scala错误:类型擦除底层的jvm。我使用的结构对于scala是非法的,因为我希望参数化特征可以通过“with”子句扩展。

    编译抱怨

    mixed.scala:53: error: illegal inheritance;
    class ArithmAccum inherits different type instances of trait Handler:
    Handler[ProdMsg] and Handler[SumMsg]
    class ArithmAccum (var store: Int) extends SumHandler with MulHandler
    

    我有哪些选择?我无法使用我设计的模式,需要通过可用性找到相同的替代品。可能anoyone建议替代源代码解决方案?是否存在scala插件(它们似乎存在于编译器中)或另一种将scala参数化类型的后端从java泛型更改为c ++(如代码生成)的方法?

1 个答案:

答案 0 :(得分:2)

您的问题不是JVM的类型擦除,而是Scala使用线性化来解析继承。

从Handler中删除类型参数[+ proto&lt;:Protocol]。无论如何,它不被handle方法使用。那么你的非法继承错误就会消失。