A look at how the Scala `lazy val` syntax gets converted into Java code (bytecode)

I don’t have any major conclusions to share in this blog post, but ... what I was curious about is how Scala implements lazy val fields. That is, when the Scala code I write is translated into a .class file and bytecode that a JVM can understand, what does that resulting code look like?

Back to top

A little `lazy val` conversion example

To look at this I created a file named Foo.scala and put the following code in it:

class Foo {
    lazy val foo = "foo " + "bar"
}

I then compiled this code with this command:

$ scalac -Xprint:all Foo.scala 

That command didn’t print out what I was looking for, so I then tried the javap command on the resulting .class file:

$ javap Foo
Compiled from "Foo.scala"
public class Foo {
    public java.lang.String foo();
    public Foo();
}

That also didn’t tell me too much, except it looks like the foo field is converted to a method. So then I used the jad command to decompile the .class file back to a Java file:

$ jad Foo

import scala.runtime.BoxedUnit;

public class Foo
{
    private String foo$lzycompute()
    {
        synchronized(this)
        {
            if(!bitmap$0)
            {
                foo = "foo bar";
                bitmap$0 = true;
            }
            BoxedUnit _tmp = BoxedUnit.UNIT;
        }
        return foo;
    }

    public String foo()
    {
        return bitmap$0 ? foo : foo$lzycompute();
    }

    public Foo()
    {
    }

    private String foo;
    private volatile boolean bitmap$0;
}

This is what I was looking for. It shows that there is a private foo field, a public foo method, and that foo method calls a private method named foo$lzycompute. The lazy magic happens in both the foo method and the foo$lzycompute method. I’m not going to take the time to explain it, but if you know Java, you can see it in that code.

Back to top

A second `lazy val` conversion example

Curious how this might grow, I added another line of code to my Scala source code:

class Foo {
    lazy val foo = "foo " + "bar"
    val baz = foo + " baz"
}

I compiled this code with scalac, then skipped the intermediate things I tried before and just decompiled the .class file with jad, and got the following output from it:

import scala.collection.mutable.StringBuilder;
import scala.runtime.BoxedUnit;

public class Foo
{

    private String foo$lzycompute()
    {
        synchronized(this)
        {
            if(!bitmap$0)
            {
                foo = "foo bar";
                bitmap$0 = true;
            }
            BoxedUnit _tmp = BoxedUnit.UNIT;
        }
        return foo;
    }

    public String foo()
    {
        return bitmap$0 ? foo : foo$lzycompute();
    }

    public String baz()
    {
        return baz;
    }

    public Foo()
    {
    }

    private String foo;
    private final String baz = (new StringBuilder()).append(foo()).append(" baz").toString();
    private volatile boolean bitmap$0;
}

The big change in that code is this line:

private final String baz = (new StringBuilder()).append(foo()).append(" baz").toString();

As a reminder, I defined baz in my Scala file like this:

val baz = foo + " baz"

and that simple line of code resulted in the private final String baz line of code shown.

Back to top

One more `lazy val` conversion example

I was going to stop there, but okay, here’s one more example. First I created this Foo.scala file:

class Foo {
    lazy val text = io.Source.fromFile("/etc/passwd").getLines.foreach(println)
}

Then I compiled it with scalac and then decompiled it with jad to get this Java source code:

import scala.Predef$;
import scala.Serializable;
import scala.collection.Iterator;
import scala.io.*;
import scala.runtime.AbstractFunction1;
import scala.runtime.BoxedUnit;

public class Foo
{

    private void text$lzycompute()
    {
        synchronized(this)
        {
            if(!bitmap$0)
            {
                Source$.MODULE$.fromFile("/etc/passwd", Codec$.MODULE$.fallbackSystemCodec()).getLines().foreach(new Serializable() {

                    public final void apply(Object x)
                    {
                        Predef$.MODULE$.println(x);
                    }

                    public final volatile Object apply(Object v1)
                    {
                        apply(v1);
                        return BoxedUnit.UNIT;
                    }

                    public static final long serialVersionUID = 0L;

                }
);
                bitmap$0 = true;
            }
            BoxedUnit _tmp = BoxedUnit.UNIT;
        }
    }

    public void text()
    {
        if(!bitmap$0)
            text$lzycompute();
    }

    public Foo()
    {
    }

    private BoxedUnit text;
    private volatile boolean bitmap$0;
}

As you can see, the simple “wrapper” code outside of the text$lzycompute method is very similar, but the text$lzycompute method itself is quite different. Once again I’m not going to comment on that code because all I want to do today is to take a quick look at how this works. If/when I feel a little less lazy, I’ll write more about this.

Back to top

The end

As I mentioned at the beginning of this post, I don’t have any major conclusions or anything here. I just wanted to take a quick look at how the Scala lazy val syntax gets converted into Java code and/or bytecode that the JVM can understand, and these examples are a start down this road.

Of course there are many more things you can do with the Scala lazy val syntax, and while I’m not going to dig into that today, these examples show how you can do that if you’re interested in looking into it.

Back to top

Add new comment

The content of this field is kept private and will not be shown publicly.

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.
By submitting this form, you accept the Mollom privacy policy.