SBN

Does my Scala Value Class really not get allocated?

Scala’s Value Classes are a powerful and widely used mechanism for extension methods and additional type safety, both without incurring the runtime overhead of an allocation. ​For example, we can provide additional methods for instances of Foo (which may well be defined in a library out of our control) as follows:

There are more examples in Scala’s documentation, which (together with AnyVal’s scaladoc) documents the limitations of this mechanism. In other words, the compiler can only avoid allocations, if all of the following are true for a given Value Class:​

  • must have only a primary constructor with exactly one public parameter whose type is not a user-defined value class
  • can define defs, but no vals, vars, or nested traits, classes or objects
  • may not have @specialized type parameters
  • may not have nested or local classes, traits, or objects
  • may not define equals or hashCode method.
  • must be a top-level class or a member of a statically accessible object
  • cannot be extended by another class​

Unfortunately, it’s not straightforward to see if the compiler really succeeded in avoiding the allocation. An annotation or compiler warning similar to @tailrec would be nice and there's a long-standing ticket on this. But it looks like we'll have to wait for Scala 3 for this. The above example is rather straightforward and can be verified by hand, but most use cases are more complicated. Also, there are alternative ways to achieve the same, e.g. implicit def instead of implicit class:

implicit def toFooExt(foo: Foo) = new FooExt(foo)

There’s an explicit allocation of FooExt here – does the compiler still optimize it out? (The answer is yes). ​And how about if we use an implicit class but no AnyVal? (Interestingly, this also does not incur an allocation at runtime):

implicit class FooExtImplicitClass(val foo: Foo) { def bar = 42 }

Back to the question: how can we verify if all the conditions are met and the compiler successfully optimized our code, so that there won’t be an allocation at runtime? The easiest and safest way I found was to decompile the .class files back to Java and search for the new keyword. In the absence of a good decompiler (like cfr) you can also use javap -c. Here is a complete and copy-pasteable example with four alternative use cases:​

Compile the file:

scalac ValueClassDebug.scala
cfr Main\$.class
#any other java decompiler will do, alternatively `javap -c`

​Thanks to Denis Yermakov for pointing me in the right direction.


Does my Scala Value Class really not get allocated? was originally published in ShiftLeft Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.


*** This is a Security Bloggers Network syndicated blog from ShiftLeft Blog - Medium authored by Michael Pollmeier. Read the original post at: https://blog.shiftleft.io/does-my-scala-value-class-really-not-get-allocated-b482e86fc3fb?source=rss----86a4f941c7da---4

Secure Guardrails