Scala value classes are a sugary-sweet convenience, but they can introduce some low-level conflicts due to their compilation magic.
First, what are they? There’s a thorough explanation in the Scala documentation, but in some useful terms: you use value classes to “wrap” a single primitive in an object. With that, you can add member methods as well as reap the benefits of the type system such as type-checking and polymorphism. How this differs from regular-old OO is that the Scala compiler will convert these types to the underlying primitive and will be allocated as such on the heap.
See these classes:
Here’s how they are compiled:
The Scala compiler will ensure that MyClass2 always takes a ValueWrapper, but will convert it to an int in the bytecode. What does this mean? Usually, not much - it all works seamlessly under the hood while saving you memory. Until you need to use reflection. Which you never, ever use, right? Unless, of course, you are trying to get a reference to an Akka actor.
This code will compile:
But it will fail at runtime:
This is frustrating because there obviously is a matching constructor, at compile time at least.
This is what happens when we try to get a reference to MyActor:
Since the compiler has optimized the costructor to take the underlying primitive type, the relefctive call fails.
There really is no solid workaround, but since you know all references of your value classes will be converted to their primitive types, you can just accept the primitive in the constructor and handle any conversions manually.