1

This is related to the following question: In scala, how to turn object's values into Map[String, String]?

In fact, I have almost exactly the same problem. However, the solution given in the accepted answer runs around 50x slower than productIterator (which returns only the values of the fields) when iterating 1000 times on my machine (or manually writing a function to return the list of (key, value) pairs). Is there a reasonably performant and clean way of getting the names of the fields of a case class in Scala? It seems strange to me that the core language would provide a performant reflection-like way of getting the values, but not the field names.

Community
  • 1
  • 1
jonderry
  • 23,013
  • 32
  • 104
  • 171
  • It's possible to get both the names and values quickly using [compile-time reflection](http://stackoverflow.com/a/17224392/334519). – Travis Brown May 27 '14 at 11:32

1 Answers1

2

If you write and compile a case class, you can browse through the generated byte code and you will notice that the field names are not hardcoded anywhere into a method of the class. This means you must use reflection for finding out about these names. And reflective lookup is unfortunately expensive.

With the productIterator, there is however an approach for avoiding reflection. Any case class implements the Product trait which defines a method Object productElement(int) which will return the value of the field at a given index. Other than the field names, this information is hardcoded into a case class method. By internally using this method, the productIterator method avoids reflection and can be executed efficiently.

Bottom line: While reflective invocation is not so expensive, reflective lookup is. If you need the field name information, you should therefore only lookup the information once and cache the results for later reuse.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • Is there a way to ensure that the members appear in the order they were declared, as with `productIterator`? I saw something about `declarations.sorted` in the class `Type`, but couldn't find a clear specification on the sort order. – jonderry May 27 '14 at 08:52
  • In theory, all fields should appear in the ordering of the source code when using a reflective invocation. This is however not specified and a JVM might choose to implement it differently. However, once you got through the reflective lookup, a reflective field read is dead cheap. IT is basically a direct heap access and you will not notice any runtime difference compared to native field access. This way, you could also retrieve unboxed instances where applicable what might even save you time. – Rafael Winterhalter May 27 '14 at 08:57
  • Even though I haven't seen a counterexample with the field ordering, I'm very worried about relying on this in production if the api went out of its way to say that the order is unspecified. For `sorted`, I still haven't found a spec describing the sort order. – jonderry May 27 '14 at 09:01
  • Where did you discover this *declarations.sorted* in `Type`? – Rafael Winterhalter May 27 '14 at 09:05
  • The scala api: abstract def members: Universe.MemberScope A Scope containing all members of this type (directly declared or inherited). Unlike declarations this method also returns inherited members. Members in the returned scope might appear in arbitrary order. Use declarations.sorted to get an ordered list of members. – jonderry May 27 '14 at 17:27
  • That is pretty new Scala 2.11 - I do not think that this would improve your situation though since it could not handle reflection more efficiently as long as it does not add a method to any class at compile time. It could of course do this for case classes but at the moment, it does not. – Rafael Winterhalter May 27 '14 at 17:36