Reputation: 2845
I need to write a generic class that can only allow the types Long,Double in place of [V]
class DummyGenericClass[V](data:Seq[V])
Also, there will be an implementation difference based on the type. I want to do something like
val typ = if (V is Long) "x" else "y"
What is the recommended/best practice in scala to write such code?
Upvotes: 0
Views: 86
Reputation: 1239
You can achieve it using sealed trait, which limits possible implementations to those that are defined in the same file:
sealed trait DummyGenericClass[V] {
val data: Seq[V]
val typ: String
}
class LongClass(val data: Seq[Long]) extends DummyGenericClass[Long] {
val typ = "x"
}
class DoubleClass(val data: Seq[Double]) extends DummyGenericClass[Double] {
val typ = "y"
}
If you want to have a generic constructor for DummyGenericClass
the type safe way to do it is to use typeclass combined with factory pattern:
object DummyGenericClass {
trait Factory[T] {
def create(seq: Seq[T]): DummyGenericClass[T]
}
object Implicits {
implicit val longProvider =
new Factory[Long] {
def create(seq: Seq[Long]) = new LongClass(seq)
}
implicit val doubleProvider =
new Factory[Double] {
def create(seq: Seq[Double]) = new DoubleClass(seq)
}
}
def apply[T: Factory](seq: Seq[T]) = implicitly[Factory[T]].create(seq)
}
Which you can use the following way:
import DummyGenericClass.Implicits._
val foo = DummyGenericClass(Seq.empty[Long])
val bar = DummyGenericClass(Seq.empty[Double])
// Won't compile:
val baz = DummyGenericClass(Seq.empty[String])
The other way, that doesn't require defining a typeclass to create DummyGenericClass
instances, is to pass ClassTag
bound to T
in the factory method. However this solution is not recommended since it's not a type safe way, as it allows one to pass type argument that is not supported and will fail at runtime.
If you want to have a generic method that uses this constructor, you have to add DummyGenericClass.Factory
context bound to that method too:
def add[T: DummyGenericClass.Factory]
(a: DummyGenericClass[T], b: DummyGenericClass[T]) =
DummyGenericClass(a.data ++ b.data)
import DummyGenericClass.Implicits._
add(DummyGenericClass(Seq(1.0)), DummyGenericClass(Seq(2.0)))
Upvotes: 3