Cracking Scala Class with Bytecode

Alexander Panman
Wix Engineering
Published in
3 min readMay 1, 2022
Photo by Fran Jacquier on Unsplash

For this article, I assume you have good knowledge of JVM bytecode (you can find my full crash course) or excellent low level programming intuition :)

I remember the first time I started to write Scala code. I was so excited after Java 8 — Scala is the language I wanted Java to be: minimum boiler plate code, no need to generate getters, setters, and other garbage code. You need singleton; get it for free. Want to write immutable code? Easy peasy (let’s put aside the functional and object oriented paradigms)

But Scala is a JVM language and fully compatible with Java (maybe even forty-second cousins? ;) So how does this magic work? What’s behind it?

Let’s take a look at the next simple class. In Scala, you have at least three different options to declare a variable:

Check out the bytecode (don’t know how? Read here):

Discussion:

val scalaValue = “string value”

Declares immutable value: scalaValue

var scalaVariable = “string variable”

Declares mutable variable: scalaVariable

def scalaDef = “string def”

Declares function: scalaDef

Notice the interesting points in bytecode that make them different.
First of all, at the beginning of the class, we discover two class fields: one scalaValue and another scalaVariable that we can’t find in the code, and two private class methods to access them:

3:   // access flags 0x12
4: private final Ljava/lang/String; scalaValue
6: // access flags 0x2
7: private Ljava/lang/String; scalaVariable

Second, methods we defined in class. All of them have the same signature:

10:  public scalaValue()Ljava/lang/String;
22: public scalaVariable()Ljava/lang/String;
49: public scalaDef()Ljava/lang/String;

Also pay attention to the existence of:

34:  public scalaVariable_$eq(Ljava/lang/String;)V

This is the public method for changing class field scalaVariable. Thus, you are able to change it in your program. scalaValue doesn’t have such a method. It is defined as final, and, therefore, immutable.
In general, there’s nothing special about the implementation of: scalaVariable_$eq . It looks like a standard setter to me:
public void setScalaVariable(String value);

The bodies of:

10:  public scalaValue()Ljava/lang/String;

and

22:  public scalaVariable()Ljava/lang/String;

are absolutely equal.

And there is more to come:
Scala compiler also generated a constructor for us with all needed initialization for the class (remember: we have two hidden fields):

60:  public <init>()V

Where you can find:

68:   LDC “string value”
69: PUTFIELD ScalaClass.scalaValue : Ljava/lang/String;

73: LDC “string variable”
74: PUTFIELD ScalaClass.scalaVariable : Ljava/lang/String;

Of course, this code is run when we create the instance of the class. Therefore, when we call scalaValue or scalaVariable methods, the values are initialized and ready.

On the other hand, when we call to

49:  public scalaDef()Ljava/lang/String;
50: L0
51: LINENUMBER 4 L0
52: LDC “string def”
53: ARETURN

We push the value from run-time constant pull into the operand stack directly.

There is also a kind of special case to consider, called ‘function,’ but the bytecode gets really complicated to explain here :( How complicated? I encourage you to check it out yourself.

class ScalaClass {
val scalaFunction: () => String = () => “scala function”
}

Good job!!!

Photo by Liudmyla Denysiuk on Unsplash

Conclusions:

Above, we used our knowledge and tools of bytecode to see how the magic of Scala works under the hood, and developed a deeper understanding of its features.There are more interesting Scala features to investigate: from simple, like how object (Scala singleton “syntactic sugar”) feature is implemented or what the price is for case class services (spoiler — even empty case class is a huge thing) to complex traits mixins (that Java developers are missing). So get out of your CRUD zones, go deeper and broaden your horizons! There are many other worlds here to explore.

links:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html
https://medium.com/wix-engineering/cracking-jvm-code-part-i-412716e84211

--

--