I used to think that private val
and private final val
are same, until I saw section 4.1 in Scala Reference:
A constant value definition is of the form
final val x = e
where e is a constant expression (§6.24). The final modifier must be present and no type annotation may be given. References to the constant value x are themselves treated as constant expressions; in the generated code they are replaced by the definition’s right-hand side e.
And I have written a test:
class PrivateVal { private val privateVal = 0 def testPrivateVal = privateVal private final val privateFinalVal = 1 def testPrivateFinalVal = privateFinalVal }
javap -c
output:
Compiled from "PrivateVal.scala" public class PrivateVal { public int testPrivateVal(); Code: 0: aload_0 1: invokespecial #19 // Method privateVal:()I 4: ireturn public int testPrivateFinalVal(); Code: 0: iconst_1 1: ireturn public PrivateVal(); Code: 0: aload_0 1: invokespecial #24 // Method java/lang/Object."<init>":()V 4: aload_0 5: iconst_0 6: putfield #14 // Field privateVal:I 9: return }
The byte code is just as Scala Reference said: private val
is not private final val
.
Why doesn't scalac just treat private val
as private final val
? Is there any underlying reason?
The main difference between private and final keywords in Java is that private is primarily an access modifier, which controls the visibility of variables, methods, and classes in Java applications, while final is just a modifier that enforces additional constraints on the field, method, and class in Java.
In Java as both private and final methods do not allow the overridden functionality so no use of using both modifiers together with same method.
Most Kotlin developers would agree that a val property is equivalent to a final property in Java. What if I tell you that this is not completely true and sometimes you might need a final val ? Opposite to Java, Kotlin properties are final by default unless they are explicitly marked as open!
In Scala, Final is a keyword and used to impose restriction on super class or parent class through various ways. We can use final keyword along with variables, methods and classes.
So, this is just a guess, but it was a perennial annoyance in Java that final static variables with a literal on the right-hand side get inlined into bytecode as constants. That engenders a performance benefit sure, but it causes binary compatibility of the definition to break if the "constant" ever changed. When defining a final static variable whose value might need to change, Java programmers have to resort to hacks like initializing the value with a method or constructor.
A val in Scala is already final in the Java sense. It looks like Scala's designers are using the redundant modifier final to mean "permission to inline the constant value". So Scala programmers have complete control over this behavior without resorting to hacks: if they want an inlined constant, a value that should never change but is fast, they write "final val". if they want flexibility to change the value without breaking binary compatibility, just "val".
I think the confusion here arises from conflating immutability with the semantics of final. val
s can be overridden in child classes and therefore can't be treated as final unless marked as such explicitly.
@Brian The REPL provides class scope at the line level. See:
scala> $iw.getClass.getPackage res0: Package = package $line3 scala> private val x = 5 <console>:5: error: value x cannot be accessed in object $iw lazy val $result = `x` scala> private val x = 5; println(x); 5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With