Pourquoi «private val» et «private final val» sont-ils différents?

J’avais l’habitude de penser que private val et private final val sont les mêmes, jusqu’à ce que je voie la section 4.1 dans la référence Scala:

Une définition de valeur constante est de la forme

 final val x = e 

où e est une expression constante (§6.24). Le modificateur final doit être présent et aucune annotation de type ne peut être donnée. Les références à la valeur constante x sont elles-mêmes traitées comme des expressions constantes; dans le code généré, ils sont remplacés par le côté droit de la définition e.

Et j’ai écrit un test:

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

javap -c sortie:

 Comstackd 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 } 

Le code d’octet est juste comme le dit Scala Reference: private val n’est pas private final val .

Pourquoi le scalac ne traite-t-il que private val private final val comme private final val ? Y a-t-il une raison sous-jacente?

Donc, ce n’est qu’une supposition, mais en Java, les variables statiques finales avec un littéral sur le côté droit deviennent des constantes. Cela engendre un avantage certain sur le plan de la performance, mais cela entraîne la rupture de la compatibilité binary de la définition si la «constante» a changé. Lors de la définition d’une variable statique finale dont la valeur pourrait devoir être modifiée, les programmeurs Java doivent recourir à des hacks comme l’initialisation de la valeur avec une méthode ou un constructeur.

Un val à Scala est déjà définitif au sens de Java. Il semble que les concepteurs de Scala utilisent le modificateur redondant final pour signifier “l’autorisation d’inclure la valeur constante”. Les programmeurs Scala ont donc un contrôle total sur ce comportement sans avoir recours à des hacks: s’ils veulent une constante intégrée, une valeur qui ne devrait jamais changer mais qui est rapide, ils écrivent “val finale”. s’ils veulent pouvoir modifier la valeur sans rompre la compatibilité binary, il suffit de “val”.

Je pense que la confusion vient de ce que l’immutabilité est associée à la sémantique de la finale. val peuvent être remplacées dans les classes enfants et ne peuvent donc pas être traitées comme définitives à moins d’être identifiées comme telles.

@Brian Le REPL fournit une étendue de classe au niveau de la ligne. Voir:

 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