Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: can compiler optimize constants efficiently?

Let's consider the following:

object Foo {
  val BUFFER_SIZE = 1024
}

class Foo {
  .
  .
  .

  val buffer = new Array[Byte](Foo.BUFFER_SIZE)

This is too verbose and doesn't seem to be elegant compared with Java's static (final) variable, especially because the definition and the usage of the constant are too far apart to understand the code immediately. What I want is something like this:

class Foo {
  val BUFFER_SIZE = 1024

  val buffer = new Array[Byte](BUFFER_SIZE)

The question is, is the Scala compiler smart enough to not instantiate BUFFER_SIZE for every instance of Foo to waste time and space? Or should go with the first one?

like image 654
K J Avatar asked Feb 15 '23 02:02

K J


1 Answers

TLDR: No, it is not so good, but you can guide the compiler.

And it's easy to check (I put the code into test.scala):

scalac test.scala 
javap Foo.class
// Compiled from "test.scala"
// public class Foo {
//   public int BUFFER_SIZE();
//   public byte[] buffer();
//   public Foo();
// }

So val ends up to be a getter method. Now let's look at the actual bytecode:

javap -c Foo.class
Compiled from "test.scala"
public class Foo {
  public int BUFFER_SIZE();
    Code:
       0: aload_0       
       1: getfield      #15                 // Field BUFFER_SIZE:I
       4: ireturn       

  // .... irrelevant parts

As you can see there is a getfield code that means there will be distinct instance for every class instance (versus getstatic which means access to static variable). Highly optimized code would look like

public final int BUFFER_SIZE();
    Code:
       0: sipush        1024
       3: ireturn 

which will be produced if you mark BUFFER_SIZE with final modifier:

class Foo {
  final val BUFFER_SIZE = 1024

  val buffer = new Array[Byte](BUFFER_SIZE)
}

Prefixing field with private[this] as @ghik said will do the trick as well. The difference is that final produces getter with trivial code, whereas private[this] directly inlines value.

like image 130
om-nom-nom Avatar answered Feb 23 '23 14:02

om-nom-nom