class Foo {
final val pi = 3
}
Does every Foo
object have a pi
member? Should I therefore put pi
in the companion object?
If you are concerned about the memory footprint, you might consider moving this field into the companion object.
Yes, every instance of class Foo
will have the pi
value -- the Scala compiler will not eliminate this declaration. The JVM reflection allows you to remove final modifiers on class members, and the Unsafe
object even allows modifying these. So -- the Scala compiler could produce code with surprising results by removing this field, so this optimization is not applied.
...
minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_SUPER
...
{
private final int pi;
flags: ACC_PRIVATE, ACC_FINAL
public final int pi();
flags: ACC_PUBLIC, ACC_FINAL
LineNumberTable:
line 243: 0
LocalVariableTable:
Start Length Slot Name Signature
...
In fact, some compiler transformations (e.g. specialization) might even remove final modifiers on members under-the-hood, so something that feels final
in Scala code might not be final
on the bytecode level.
This:
class Foo[@specialized T] {
final val pi: T = null.asInstanceOf[T]
}
becomes:
...
public final T pi;
flags: ACC_PUBLIC, ACC_FINAL
Signature: #9 // TT;
public T pi();
flags: ACC_PUBLIC
LineNumberTable:
line 243: 0
...
Above, the pi
accessor method (i.e. its getter) is no longer final.
And neither will the JIT in the Oracle JVM remove this member from the object representation in memory at runtime - the runtime size of the Foo
object on a 32-bit JVM will be 16 bytes (8 bytes object header + 4 bytes for an integer field, rounded to an 8 byte boundary). The JIT might, however, decide to inline the constant value from the final field into parts of the code, so that some field writes are eliminated.