Composition with the same trait, but different type parameters

I'm currently wondering about composing an object/class/trait that conforms to one trait for multiple type parameters. Let's say I have

trait Dependent[T]{
  def observeCritereaChanged(oldValue:T, newValue:T):Unit
}

I would like to be able to define some trait that implements Dependent for two different type parameters, for example

trait IntStrDependent extends Dependent[Int] with Dependent[String]

So that instances of my IntStrDependent trait would have to define the observeCritereaChanged for both types:

class MyDependent extends IntStrDependent {
  def observeCritereaChanged(oldValue:Int, newValue:Int) = //...
  def observeCritereaChanged(oldValue:String, newValue:String) = //...
}

So far my efforts have been met with a compile error when trying to create the IntStrDependent trait:

scala> trait IntStrDependent extends Dependent[Int] with Dependent[String]
<console>:8: error: illegal inheritance;
 self-type IntStrDependent does not conform to Dependent[Int]'s selftype Dependent[Int]
       trait IntStrDependent extends Dependent[Int] with Dependent[String]
                                     ^
<console>:8: error: illegal inheritance;
 self-type IntStrDependent does not conform to Dependent[String]'s selftype Dependent[String]
       trait IntStrDependent extends Dependent[Int] with Dependent[String]
                                                         ^

So my question is: Is there a way to do what I'm trying to do (if so, how) or is this a lost cause because Scala isn't built to do this kind of thing?


Good question. I don't think you can do what you want directly.

One alternative approach is trait IntStrDependent extends Dependent[Either[Int, String]] but that doesn't quite solve the problem. Maybe a variant of Miles Sabin's encoding of union types allows something fancier to be done.

I think the best option is to keep it simple,

trait Dependent[T]{
  def observeCritereaChanged(oldValue:T, newValue:T):Unit
}

trait IntStrDependent {
  val I: Dependent[Int]
  val S: Dependent[String]
}

object MyDependent extends IntStrDependent {
  object I extends Dependent[Int] {
    def observeCritereaChanged(oldValue:Int, newValue:Int) {}
  }
  object S extends Dependent[String] {
    def observeCritereaChanged(oldValue:String, newValue:String) {}
  }
}

To use MyDependent , one must explicitly select the Int or String variant, as in

MyDependent.I.observeCritereaChanged(1, 2)

In my opinion, making the type dependence explicit is a good thing anyway.

链接地址: http://www.djcxy.com/p/9036.html

上一篇: OOP:我如何处理有相互关系的对象?

下一篇: 组成具有相同的特征,但具有不同的类型参数