scalarefinement-type

Can I force certain keys in a map to have certain types in scala?


For example, I know that at runtime I will have only the following keys: string-key-1, number-key-1.

I can create a map of key to typed value like this:

sealed trait Container {
  type T

  def resolve: T = this match {
    case StringContainer(s) => s.asInstanceOf[String]
    case BigDecimalContainer(n) => n.asInstanceOf[BigDecimal]
    // and more
  }
}


final case class StringContainter(v: String) { type T = String } 
final case class BigDecimalContainer(v: BigDecimal) { type T = BigDecimal } 

Then I could enforce types like this:

Map[String, Container]

But that still requires the client to know that a string-key-1 type cannot map to a BigDecimalContainer. Is there any way to create logic that internally maps tuples of (key, container type) => value? Some sort of implicit predicate function is probably what I need, no?


Solution

  • You can use shapless hmap:

    class KeyToValue[K, V]
    case class StringKey(key: String)
    case class IntKey(key: String)
    implicit val keyToString = new KeyToValue[StringKey, String]
    implicit val keyToInt = new KeyToValue[IntKey, Int]
    
    val map = HMap[KeyToValue](
        StringKey("string-key") -> "string-value",
        IntKey("int-key") -> 0
    )
    
    val stringValueOption = map.get(StringKey("string-key")) //will be Some("string-value")
    val intValueOption = map.get(IntKey("int-key")) //will be Some(0)