Почему `private val` и` private final val` отличаются?

Раньше я думал, что private val и private final val такие же, пока я не увидел раздел 4.1 в Scala Reference:

Определение постоянной величины имеет вид

 final val x = e 

где е – постоянное выражение (§6.24). Последний модификатор должен присутствовать, и аннотация типа типа не может быть задана. Ссылки на постоянное значение x сами рассматриваются как постоянные выражения; в сгенерированном коде они заменяются правой частью е.

И я написал тест:

 class PrivateVal { private val privateVal = 0 def testPrivateVal = privateVal private final val privateFinalVal = 1 def testPrivateFinalVal = privateFinalVal } 

javap -c :

 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."":()V 4: aload_0 5: iconst_0 6: putfield #14 // Field privateVal:I 9: return } 

Байт-код точно так же, как в Scala Reference: private val не является private final val .

Почему scalac просто не обрабатывает private val как private final val ? Есть ли какая-то основная причина?

    Итак, это всего лишь предположение, но настойчивое раздражение в Java заключалось в том, что конечные статические переменные с литералом с правой стороны встраиваются в байт-код в качестве констант. Это дает уверенность в производительности, но при этом бинарная совместимость определения ломается, если «константа» когда-либо изменилась. При определении конечной статической переменной, значение которой может потребоваться изменить, программистам на Java приходится прибегать к хакам, таким как инициализация значения с помощью метода или конструктора.

    Вал в Scala уже является окончательным в смысле Java. Похоже, что дизайнеры Scala используют окончательный вариант модификатора, означающий «разрешение на встраивание постоянного значения». Поэтому программисты Scala имеют полный контроль над этим поведением, не прибегая к хакам: если они хотят встроенную константу, значение, которое никогда не должно меняться, но быстро, они пишут «final val». если они хотят гибкости для изменения значения без нарушения бинарной совместимости, просто «val».

    Я думаю, что путаница здесь возникает из объединения неизменности с семантикой финала. val s может быть переопределено в дочерних classах и поэтому не может рассматриваться как окончательный, если не указано явно как таковое.

    @Brian REPL предоставляет class scope на линейном уровне. Видеть:

     scala> $iw.getClass.getPackage res0: Package = package $line3 scala> private val x = 5 :5: error: value x cannot be accessed in object $iw lazy val $result = `x` scala> private val x = 5; println(x); 5 
    Давайте будем гением компьютера.