wipman
wipman

Reputation: 581

Get a Type from a String

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 Strings 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

Answers (1)

Tim
Tim

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

Related Questions