Por qué implementa el método abstracto usando val y call desde la superclase en la expresión val return NullPointerException
Tengo una clase abstracta con un método no implementadonumbers
que devuelve una lista de números, y este método se utiliza en otra inicialización de la propiedad val:
abstract class Foo {
val calcNumbers = numbers.map(calc)
def numbers: List[Double]
}
La clase implementadora implementa utilizando una expresión val:
class MainFoo extends Foo {
val numbers = List(1,2,3)
}
Esto se compila bien, pero en tiempo de ejecución arroja una NullPointerException y apunta a la línea deval calcNumbers
:
[error] (run-main-0) java.lang.ExceptionInInitializerError
[error] java.lang.ExceptionInInitializerError
...
[error] Caused by: java.lang.NullPointerException
...
Sin embargo, cuando cambié el método implementado para def, funciona:
def numbers = List(1,2,3)
¿Porqué es eso? ¿Tiene algo que ver con el orden de inicialización? ¿Cómo se puede evitar esto en el futuro ya que no hay error / advertencia en tiempo de compilación? ¿Cómo permite Scala esta operación insegura?