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?

questionAnswers(1)

yourAnswerToTheQuestion