2011-07-09 27 views
4

我對scala非常陌生,尋求適應scala特定模式的工作正在進行中。 目標是分離消息處理和消息生成。代表消息處理的基本協變參數化類型。具體的實現可以通過常規混合或者通過混合基礎協議來實現。具有相同參數化類型的Scala mixins

的質量要求是:

  1. 延伸simaple儘可能

  2. 是類型安全的,以防止愚蠢的錯誤

我特地用乾淨的示例代碼(包含定義和使用):

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類型

我幾乎達到了我的目標,但遇到了一個大的錯誤:刪除底層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插件(它們似乎存在編譯器)或另一種方法來改變從Java泛型到C++的scala參數化類型的後端,如代碼生成?

+0

我有同樣的問題。 F ** k JVM。 – iron9light

回答

2

你的問題不是JVM的類型擦除,而是Scala使用線性化來解決繼承問題。

從Handler中刪除類型參數[+ proto <:Protocol]。無論如何,它不被處理方法使用。那麼你的非法繼承錯誤將會消失。

+0

但我會失去這種安全類型。第四個例子會被非法編譯 – ayvango

+0

但是您的類型安全只是想象中的。處理方法沒有使用類型參數proto,因此您不能確保處理程序[A]可以真正處理類型A的協議。 –

+0

此外,我不認爲您當前的解決方案按預期工作。在對象三中,用ProdMsg定義類型Proto = SumMsg。這意味着它只接受Sums *和* Prods協議。但是你可能想要的是Sums *或者* Prods。如果我沒有記錯的話,你不能在Scala中輕鬆編碼這種類型。 –

相關問題