Search code examples
scalaconstructorfinal

Meaning of final for Scala constructor arguments and class/trait/object members


What does final mean for Scala constructor arguments? I have this example:

class IntFinalTest(
    val intVal: Int,
    final val finalIntVal: Int,
    var intVar: Int,
    final var finalIntVar: Int) {
  //  intVal = 3 // error: reassignment to val
  //  finalIntVal = 3 // error: reassignment to val
  intVar = 3
  finalIntVar = 3
}

class ArrayFinalTest(
    val arrayVal: Array[Int],
    final val finalArrayVal: Array[Int],
    var arrayVar: Array[Int],
    final var finalArrayVar: Array[Int]) {
  arrayVal(0) = 3
  finalArrayVal(0) = 3
  arrayVar(0) = 3
  finalArrayVar(0) = 3
}

Judging by the compiler output (only the two marked lines result in an error), there is no difference between final and non-final vals and vars - is this correct? I have verified by running this example that all variables except for intVal and finalIntVal do get modified.

Related question RQ1: Does final have any significance in constructors of classes that are part of a hierarchy?

Related question RQ2: How do I create an immutable Array[Int] class member if it's part of constructor argument list?

Context: I use Scala 2.10.5 and only have a few months of experience with it.


Solution

  • A val cannot be changed. A val can however be overridden, so even if you see a val somewhere, you can't know its value for sure. (In the general case, it is hard to tell whether a member is overridden or not. This is known as Class Hierarchy Analysis and is equivalent to solving the Halting Problem.)

    A final val, however cannot be changed and cannot be overridden, so you know that its value can never be different than the one it was initialized with. Constructor parameters which are annotated with var or val become members of the class, and so final val for a constructor parameter really means more or less the same thing as it does for a "normal" class/trait/object member.

    Note that for (non-constructor) members declared exactly like this:

    final val foo = e
    

    i.e. with an explicit final modifier (even if the val were otherwise implicitly final, e.g. because it is inside a final class or inside an object), without a type annotation, and where e is a constant expression, the declaration becomes a constant value declaration which the Scala Language Specification guarantees to be optimized by the compiler.