Eu costumava pensar assim private val
e private final val
são os mesmos, até que vi a seção 4.1 na Referência de Scala:
Uma definição de valor constante está na forma
final val x = e
onde e é uma expressão constante (§6.24). O modificador final deve estar presente e nenhuma anotação de tipo pode ser fornecida. As referências ao valor constante x são tratadas como expressões constantes; no código gerado, eles são substituídos pelo lado direito da definição e.
E eu escrevi um teste:
class PrivateVal {
private val privateVal = 0
def testPrivateVal = privateVal
private final val privateFinalVal = 1
def testPrivateFinalVal = privateFinalVal
}
javap -c
resultado:
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
}
O código de byte é exatamente como o Scala Reference disse: private val
não é private final val
.
Por que o scalac não trata apenas private val
como private final val
? Existe alguma razão subjacente?
val
já é imutável, por que precisamos dafinal
palavra-chave em Scala? Por que o compilador não pode tratar todos osval
s da mesma maneira quefinal val
s?private
modificador de escopo tem a mesma semânticapackage private
do Java. Você pode querer dizerprivate[this]
.private
quer dizer que só é visível para instâncias desta classe,private[this]
apenas esta instância - exceto para instâncias da mesma classe ,private
não permite que ninguém (incluir do mesmo pacote) acesse o valor.Respostas:
Portanto, isso é apenas uma suposição, mas era um aborrecimento perene em Java que as variáveis estáticas finais com um literal no lado direito fossem embutidas no bytecode como constantes. Isso gera um benefício de desempenho com certeza, mas faz com que a compatibilidade binária da definição seja interrompida se a "constante" for alterada. Ao definir uma variável estática final cujo valor pode precisar ser alterado, os programadores Java precisam recorrer a hacks, como inicializar o valor com um método ou construtor.
Um val em Scala já é final no sentido de Java. Parece que os designers do Scala estão usando o modificador redundante final para significar "permissão para embutir o valor constante". Assim, os programadores de Scala têm controle total sobre esse comportamento sem recorrer a hacks: se quiserem uma constante embutida, um valor que nunca deve mudar, mas é rápido, eles escrevem "valor final". se eles querem flexibilidade para alterar o valor sem quebrar a compatibilidade binária, apenas "val".
fonte
private val
paraprivate final val
?val
no seu segundo parágrafo?Acho que a confusão aqui surge de confundir imutabilidade com a semântica do final.
val
s podem ser substituídos em classes filhas e, portanto, não podem ser tratados como finais, a menos que sejam marcados como tal explicitamente.@Brian O REPL fornece escopo de classe no nível de linha. Vejo:
fonte
private val
. Pode ser anulado?