Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Composition with the same trait, but different type parameters

Tags:

generics

scala

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?

like image 634
Dylan Avatar asked Aug 14 '11 05:08

Dylan


People also ask

Can traits have parameters?

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.

What are type parameters in Scala?

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.

Can trait extend class?

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.

Can trait have constructor in Scala?

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.


1 Answers

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.

like image 89
Kipton Barros Avatar answered Nov 15 '22 05:11

Kipton Barros