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?
Traits are used to share interfaces and fields between classes. They are similar to Java 8's interfaces. Classes and objects can extend traits, but traits cannot be instantiated and therefore have no parameters.
Methods in Scala can be parameterized by type as well as by value. The syntax is similar to that of generic classes. Type parameters are enclosed in square brackets, while value parameters are enclosed in parentheses.
Traits are reusable components that can be used to extend the behavior of classes. They are similar to interfaces and contain both abstract and concrete methods and properties.
In scala, trait is almost same as abstract class except that it can't have constructor. You can't extend multiple abstract classes but can extend multiple traits.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With