In a previous post I’ve shown how to build a minimal example of a random case class generator using the metaprogramming features of Scala 3. While investigating this topic, I naturally came upon multiple ways to do this. In this post I will elaborate on two other ways to build the same generator and pick my personal favorite.
A short story from reflection to shapeless
Coming from a Java background, reflection to me was a useful, albeit highly advanced tool in daily work. Being mostly used in libraries and frameworks, understanding its possibilities and usages was usually enough for me.
While advancing my career and moving to the scala ecosystem I learned about the existence of macros as a kind of compile-time reflection, used mostly by libraries. Still, it being a highly advanced language feature and not very ergonomic for daily programming, I felt more comfortable in the regular code world.
Then, during the development of a certain feature for the client I was working at, I felt the code I had written was so much boilerplate, there should be a way to shorten what I’ve written (unfortunately I cannot remember exactly what that was about, but it definitely had to do with some kind of mapping between data and their corresponding case classes…). In Java I would have tried my hand at reflection to extract and generate POJO’s, which could be done in scala as well, but I’ve always felt reflection isn’t the right tool for custom written production code, it being a slow, purely runtime process, which is never optimized by the compiler. I asked a senior colleague if using a macro to extract the field names and values would be a way to solve this, since it would bring me some compile-time safety. He then introduced me to the shapeless library, and the rabbit-hole opened up.