Search code examples
scalagenericsshapeless

Generate Shapeless Record from Generics


I have this standard Shapeless code:

case class KeyValue(key: String, value: Int)
val kv = KeyValue("key", 1)

def processCaseClass(p: KeyValue) = {
     val gen = LabelledGeneric[KeyValue] 
     gen.to(p)
}

But instead of using the name of the case class, I'd like to use generics, however, rewriting it this way, does not work:

def processCaseClass[KV <: Product, L <: HList](p: KV) = {
     val gen = LabelledGeneric.Aux[KV, L] 
     gen.to(p)
}

If I change gen to an implicit parameter it works OK.

What is wrong with the above code?


Solution

  • Making a method generic in T makes it clueless as to what T is. If processCaseClass doesn't know what KV is, it stands no chance of analyzing its structure enough to make a LabelledGeneric[KV], producing an implicit resolution error. By making it an implicit parameter, you shift the responsibility of producing the LabelledGeneric to the caller, where it actually stands a chance of being satisfied, because the caller will know what PK is.

    An odd thing that your first definition of processCaseClass does is this, which should suffice to show that it cannot be correct:

    def processCaseClass[KV <: Product, L <: HList](p: KV): Any // Signature of pCC
    // Function body doesn't affect sig., aside from return type, so what you write is what you get
    // A sig. is the only interface between a method and the world. This method doesn't
    // say there's a relationship between KV and L in its signature, so there doesn't
    // need to be one.
    
    // Instantiate KV = (Int, Int), L = String :: String :: HNil, p = (5, 5)
    val x = processCaseClass[(Int, Int), String :: String :: HNil]((5, 5))
    // Perfectly valid to the compiler... but what is this supposed to do?