Greedy Coder Greedy Coder - 2 months ago 7
Scala Question

Scala - How is val immutability guaranteed at run time

When we create a final in java it is guaranteed that it cannot be changed even at run time because the JVM guarantees it.

Java class:

public class JustATest {
public final int x = 10;
}


Javap decompiled:

Compiled from "JustATest.java"

public class JustATest {
public final int x;

public JustATest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 10
7: putfield #2 // Field x:I
10: return
}


But in scala, if we declare a
val
, it compiles into a normal integer and there is no difference between var and val in terms of decompilation output.

Original Scala class:

class AnTest {

val x = 1
var y = 2
}


Decompiled output:

Compiled from "AnTest.scala"
public class AnTest {
public int x();
Code:
0: aload_0
1: getfield #14 // Field x:I
4: ireturn

public int y();
Code:
0: aload_0
1: getfield #18 // Field y:I
4: ireturn

public void y_$eq(int);
Code:
0: aload_0
1: iload_1
2: putfield #18 // Field y:I
5: return

public AnTest();
Code:
0: aload_0
1: invokespecial #25 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: putfield #14 // Field x:I
9: aload_0
10: iconst_2
11: putfield #18 // Field y:I
14: return
}


With that information, the concept of immutability of a
val
is controlled only at compile time by the scala compiler? How is this guaranteed at run time?

Answer

In Scala, conveying immutability via val is a compile time enforcement which has nothing to do with the emitted byte code. In Java, you state that the field is final in order for it not to be overridden or reassigned, where in Scala, declaring a variable with val only means it can't be reassigned, but it can be overridden. If you want a field to be final, you'll need to specify it as you do in Java:

class AnTest {
  final val x = 10
}

Which yields:

public class testing.ReadingFile$AnTest$1 {
  private final int x;

  public final int x();
    Code:
       0: bipush        10
       2: ireturn

  public testing.ReadingFile$AnTest$1();
    Code:
       0: aload_0
       1: invokespecial #19                 // Method java/lang/Object."<init>":()V
       4: return
}

Which is equivalent to the byte code you see in Java, except the compiler has emitted a getter for x.