Say I have a case class that has a type parameter T:
case class ProdutOption[T](name: String, value:T)
And this case class is contained in another case class like:
case class Product[T](id: String, options: Set[ProductOption[T]])
What is the correct way to model this?
I want my options
parameter to be able to have different types of T... I don't want all items in the set to be forced to a specific type.
Is this scenario possible to model using type parameters like this?
CodePudding user response:
Everything depends on whether your set of possible option types is closed (i.e. known statically) or open (unknown until runtime) and how exactly do you want to process these options.
If you can enumerate all possible options, use an ADT (algebraic data type):
sealed trait ProductOption[ T] {
def name: String
def value: T
}
object ProjectOption {
case class SomeNumericOption(value: Int) extends ProductOption[Int] {
def name: String = "numeric"
}
case class SomeTextualOption(value: String) extends ProductOption[String] {
def name: String = "textual"
}
}
case class Product(id: String, option: Set[ProductOption[_]])
You can then process these options in a type-safe way using pattern matching.
If your option hierarchy is not known then you should introduce some method for processing this option into the base trait, which will no longer be sealed
:
trait ProductOption {
def name: String
def processMe(): Whatever = ...
}
case class Product(id: String, option: Set[ProductOption])
What exactly would processMe
do depends on your use case.
This is a classical example of so called expression problem.
CodePudding user response:
It's a little unclear what exactly you're looking for, but it may be useful to consider covariance for ProductOption
:
case class ProductOption[ T](name: String, value: T)
This says that if S
is a supertype of T
, ProductOption[T]
is a subtype of ProductOption[S]
.
Specifically this then means that a Product[Any]
allows options
to be any kind of ProductOption
:
Product("my favorite product", Set(ProductOption[String]("color", "blue"), ProductOption[ShirtSize]("size", ShirtSize.TwoXL)) // type is Product[AnyRef]