Reputation: 15435
I have a trait which is generic and goes like this:
trait MyTrait[T] {
def doSomething(elems: Seq[T])
}
I then have a object factory whose definition goes like this:
object MyTraitFactory {
def apply[T](param1: Boolean, param2: Boolean): MyTrait[T] = {
// based on the type of T, I would like to instantiate sub types
}
}
I have come concrete implementations that are for example:
class MyStringTrait extends MyTrait[String]
class MyIntTrait extends MyTrait[Int]
I now need that magic bit that would look for the type in my object factory and instantiate the corresponding implementations. Any suggestions?
Upvotes: 3
Views: 698
Reputation: 85
This can be solved in scala using an implicit typeclass. Create a factory trait with concrete implementations for each of your types:
object MyTraitFactory {
def apply[T](param1: Boolean, param2: Boolean)(implicit factory: MyTraitCreator[T]): MyTrait[T] = {
// call the typeclass create method
factory.create(param1, param2)
}
// factory trait
trait MyTraitCreator[T] {
def create(param1: Boolean, param2: Boolean): MyTrait[T]
}
// provide an implicit factory object for the specific types:
object MyTraitCreator {
implicit object MyStringTraitCreator extends MyTraitCreator[String] {
override def create(param1: Boolean, param2: Boolean): MyTrait[String] = {
// create the String type here
new MyStringTrait
}
}
implicit object MyIntTraitCreator extends MyTraitCreator[Int] {
override def create(param1: Boolean, param2: Boolean): MyTrait[Int] = {
// create the Int type here
new MyIntTrait
}
}
}
}
Scala "hides" the typeclass using the implicit parameter. But for this to work, you have to ensure to keep the implicit factory objects somewhere the compiler looks for implicits (e.g. the companion object to MyTraitCreator
as above). The pattern works just as well without the implicit
but then needs the caller to supply the concrete factory on each call.
This solution includes a lot of boiler plate code but works statically at compile time and does not suffer from type erasure. It even comes with syntactic sugar in scala:
def apply[T: MyTraitCreator](param1: Boolean, param2: Boolean): MyTrait[T] = {
// call the typeclass create method
implicitly[MyTraitCreator[T]].factory.create(param1, param2)
}
Upvotes: 4