Reputation: 4743
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?
Upvotes: 4
Views: 404
Reputation: 62835
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.
Upvotes: 6
Reputation: 10764
It will never be optimized out like this, because it's a member that has to be available from outside (e.g. from Java).
The only situation when it may be optimized out (in the future) is when it's declared as private[this]
:
class Foo {
private[this] val BUFFER_SIZE = 1024
val buffer = new Array[Byte](BUFFER_SIZE)
}
Anyway, I would still say that the way to go is to use companion object.
Upvotes: 2