I'm still pretty new to Scala, but I know you can define class variables that are initialized in the constructor like
class AClass(aVal: String)
which would be like doing the following in java
class AClass {
private String aVal;
public AClass(String aVal) {
this.aVal = aVal;
}
}
In Java, I would declare aVal as final. Is there a way to make the aVal variable final in the Scala syntax?
EDIT: Here is what I am seeing when I compile the following Scala class:
class AClass(aVal: String) {
def printVal() {
println(aVal)
}
}
I ran javap -private
and got the output
public class AClass extends java.lang.Object implements scala.ScalaObject{
private final java.lang.String aVal;
public void printVal();
public AClass(java.lang.String);
}
When I change the scala class definition to have class AClass(**val** aVal: String)
I get the following output from javap -private
public class AClass extends java.lang.Object implements scala.ScalaObject{
private final java.lang.String aVal;
public java.lang.String aVal();
public void printVal();
public AClass(java.lang.String);
}
The public method aVal
is generated. I'm still learning here - can anyone explain why that is generated?
Note I am using scala 2.9
class AClass(aVal: String)
In this code, aVal is a final variable. So You already have a final variable.
class AClass(val aVal: String)
In this code, aVal is final and you have getter of aVAl. So you can use it like below
scala> val a= new AClass("aa")
a: A1 = A1@1d7d58f
scala> a.aVal
res2: String = aa
And finally,
class AClass(var aVal: String)
In this code, aVal is not final and you have getter and setter of aVal. So you can use it like below
scala> val a= new AClass("aa")
a: AClass = AClass@1c059f6
scala> a.aVal
res3: String = aa
scala> a.aVal = "bb"
a.aVal: String = bb
scala> a.aVal
res4: String = bb
Copied from my answer: Scala final vs val for concurrency visibility
There are two meanings of the term final
: a) for Scala fields/methods and Java methods it means "cannot be overridded in a subclass" and b) for Java fields and in JVM bytecode it means "the field must be initialized in the constructor and cannot be reassigned".
Class parameters marked with val
(or, equivalently, case class parameters without a modifier) are indeed final in second sense, and hence thread safe.
Here's proof:
scala> class A(val a: Any); class B(final val b: Any); class C(var c: Any)
defined class A
defined class B
defined class C
scala> import java.lang.reflect._
import java.lang.reflect._
scala> def isFinal(cls: Class[_], fieldName: String) = {
| val f = cls.getDeclaredFields.find(_.getName == fieldName).get
| val mods = f.getModifiers
| Modifier.isFinal(mods)
| }
isFinal: (cls: Class[_], fieldName: String)Boolean
scala> isFinal(classOf[A], "a")
res32: Boolean = true
scala> isFinal(classOf[B], "b")
res33: Boolean = true
scala> isFinal(classOf[C], "c")
res34: Boolean = false
Or with javap
, which can be conveniently run from the REPL:
scala> class A(val a: Any)
defined class A
scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
private final java.lang.Object a;
public java.lang.Object a();
public A(java.lang.Object);
}
If the class parameter of a non-case class is not marked as a val
or var
, and it is not referred to from any methods, it need only be visible to the constructor of the class. The Scala compiler is then free to optimize the field away from the bytecode. In Scala 2.9.1, this appears to work:
scala> class A(a: Any)
defined class A
scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
public A(java.lang.Object);
}