Reputation: 581
I am trying to switch my code to a component-oriented design.
My point of contention is the following function do()
which matches its s
argument with some priorily known String
s and calls compute()
with the adequate type parameter.
def do(s: String, summoner: Summoner): String = {
s match {
case "a" => summoner.compute[Type_A](outOfScopeVal)
case "b" => summoner.compute[Type_B](outOfScopeVal)
case _ => ""
}
}
I would like to transpose it to a generic trait
that can be extended
if any new Type_x
is required.
[EDIT] It would be a library that external developers can enrich at will, adding a new match between a String identifier and a type.
[EDIT2] I call a library defined like the following:
trait TypeHolder[T <: Type_top] {def score(...): String}
object Converters {
implicit object ConverterOfA extends TypeHolder[Type_A] {
def convertAndMore(...): String = {
/*
compute and return a String
*/
}
}
implicit object ConverterOfB extends TypeHolder[Type_B] {
def convertAndMore(...): String = {
/*
compute and return a String
*/
}
}
}
case class Summoner(...) {
def compute[T <: Type_top](...)(implicit summoner: TypeHolder[T]): String = {
summoner.convertAndMore(...)
}
}
This problem can be reduced to getting a generic tool that returns (some kind of) a type
based on an input String.
This question: https://stackoverflow.com/a/23836385/3896166, nears the expected solution but I can not match the requirement of "know[ing] the type of object mapping names ahead of time" as the input String is received dynamically...
Also, Shapeless
might be the path to follow, but I merely started going down that path.
Is it even possible?
Upvotes: 2
Views: 147
Reputation: 27356
You could solve this by converting a String
to a type
(if that were possible), but it is not the only way of solving your underlying problem. (This is therefore an XY question)
Instead, you need to build a Map
that takes you from the String
to a method that computes the appropriate function. It might work something like this:
def computeFn[T <: Type_top] =
(summoner: Summoner, value: ???) => summoner.compute[T](value)
val computeMap = Map(
"a" -> computeFn[Type_A],
"b" -> computeFn[Type_B]
)
def do(s: String, summoner: Summoner): String =
computeMap(s)(summoner, outOfScopeVal)
It should be straightforward to adapt this so that subclasses can add to the computeMap
object in order to define their own mappings.
Upvotes: 1