Por que implementar o método abstrato usando val e call da superclasse na expressão val retorna NullPointerException
Eu tenho uma classe abstrata com um método não implementadonumbers
que retorna uma lista de números e esse método é usado em outra inicialização de propriedade val:
abstract class Foo {
val calcNumbers = numbers.map(calc)
def numbers: List[Double]
}
A classe de implementação implementa usando uma expressão val:
class MainFoo extends Foo {
val numbers = List(1,2,3)
}
Isso é compilado, mas, em tempo de execução, gera uma NullPointerException e aponta para a linha deval calcNumbers
:
[error] (run-main-0) java.lang.ExceptionInInitializerError
[error] java.lang.ExceptionInInitializerError
...
[error] Caused by: java.lang.NullPointerException
...
No entanto, quando mudei o método implementado para def, ele funciona:
def numbers = List(1,2,3)
Por que é que? Tem algo a ver com a ordem de inicialização? Como isso pode ser evitado no futuro, pois não há erro / aviso em tempo de compilação? Como o Scala permite essa operação insegura?