Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enumerate shapeless Record and access field keys in runtime?

I am writing generic code for processing lists of case class instances, collecting values in each field, combining and then passing it to the library.

Using shapeless LabelledGeneric and polymorphic functions, it looks like this:

object toNamedSingletonListOfValues extends Poly1 {
  implicit def caseField[K,T] = 
    at[FieldType[K, T]](field => { field.key -> List[T](field) })
}

val generic = LabelledGeneric[MyClass]
val records = listOfMyClassInstances.map(generic.to)
val values = records.map(_.map(toNamedSingletonListOfValues)) // Then combining and passing

However, I need a way of getting field.key because the library needs the parameter names.

Would you mind suggesting the solution?

like image 803
Uspenskiy Vladimir Avatar asked Jul 09 '14 07:07

Uspenskiy Vladimir


2 Answers

You can access the key (which is known at compile-time) as a runtime value through an instance of the Witness type class:

object toNamedSingletonListOfValues extends Poly1 {
  implicit def caseField[K, T](implicit wk: Witness.Aux[K]) = 
    at[FieldType[K, T]](field => { wk.value -> List[T](field) })
}

No need for runtime reflection!

like image 163
Travis Brown Avatar answered Oct 16 '22 10:10

Travis Brown


Found dirty hack is to make Poly look like:

import scala.reflect.runtime.universe._

object toNamedSingletonListOfValues extends Poly1 {
  implicit def caseField[K: TypeTag, T] = at[FieldType[K, T]] { field =>
    (typeOf[K] match { case TypeRef(_, _, args) => args }).last.toString.drop("java.lang.String(\"".size).dropRight(2) -> List[T]()
  }
}

Is there a nicer solution around?

like image 25
Uspenskiy Vladimir Avatar answered Oct 16 '22 08:10

Uspenskiy Vladimir