Dlaczego `private val " i "Private final val" różnią się od siebie?

Kiedyś myślałem, że private val i private final val są takie same, dopóki nie zobaczyłem sekcji 4.1 w Scali Reference:

Definicja wartości stałej ma postać

final val x = e

Gdzie e jest wyrażeniem stałym (§6.24). Ostateczny modyfikator musi być obecny i nie może być podana adnotacja o typie. Odniesienia do stałej wartości x są same w sobie traktowane jako wyrażenia stałe; w wygenerowanym kodzie są zastępowane przez definicję po prawej stronie e.

I mam napisał test:

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

javap -c wyjście:

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
}

Kod bajtowy jest tak jak Scala Reference powiedział: private val nie jest private final val.

Dlaczego scalac nie traktuje private val jako private final val? Czy jest jakiś powód?

Author: Beryllium, 2012-11-16

2 answers

Jest to więc tylko zgadywanie, ale w Javie było to odwieczną irytacją, że końcowe zmienne statyczne z literałem po prawej stronie są wstawiane do kodu bajtowego jako stałe. Powoduje to pewne korzyści wydajnościowe, ale powoduje złamanie binarnej zgodności definicji, jeśli "stała" kiedykolwiek się zmieniła. Definiując ostateczną zmienną statyczną, której wartość może wymagać zmiany, Programiści Javy muszą uciekać się do hacków, takich jak inicjalizacja wartości metodą lub konstruktor.

Val w Scali Jest już ostateczny w sensie Javy. Wygląda na to, że projektanci Scali używają redundantnego modyfikatora final, co oznacza "pozwolenie na wpisanie stałej wartości". Tak więc programiści Scali mają pełną kontrolę nad tym zachowaniem bez uciekania się do hacków: jeśli chcą wbudowanej stałej, wartości, która nigdy nie powinna się zmieniać, ale jest szybka, piszą "final val". jeśli chcą zmienić wartość bez łamania kompatybilności binarnej, wystarczy "val".

 78
Author: Steve Waldman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-25 23:33:50

Myślę, że zamieszanie tutaj wynika z połączenia niezmienności z semantyką ostatecznego. val s mogą być nadpisywane w klasach potomnych i dlatego nie mogą być traktowane jako ostateczne, chyba że są wyraźnie oznaczone jako takie.

@Brian REPL zapewnia zakres klasy na poziomie liniowym. Zobacz:

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
 7
Author: Connor Doyle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-18 05:31:22