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 开发者_JS百科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.
精彩评论