Assertions in abstract superclass scala creating NPE

走远了吗. 提交于 2019-12-31 03:06:08

问题


The following code, when entered in REPL

abstract class A { val aSet: Set[Int]; require(aSet.contains(3)) }

class B extends A { val aSet = Set(4,5,6) }

new B()

gives a null point exception, rather than an invariant failure.

What would be the best idiom to solve this problem?


Similar questions:

Code Contracts: Invariants in abstract class

Private constructor in abstract class Scala?

and also online commentary: https://gist.github.com/jkpl/4932e8730c1810261381851b13dfd29d


回答1:


When you declare a val, several things happen:

  1. The compiler makes sure that enough space is allocated for the variable when an instance of the class is initialized
  2. An accessor-method is created
  3. Initializers that setup the initial values of the variables are created.

Your code

abstract class A { val aSet: Set[Int]; require(aSet.contains(3)) }
class B extends A { val aSet = Set(4,5,6) }
new B()

is roughly equivalent to

abstract class A { 
  private var aSet_A: Set[Int] = null
  def aSet: Set[Int] = aSet_A
  require(aSet.contains(3)) 
}

class B extends A {
  private var aSet_B: Set[Int] = Set(4,5,6) 
  override def aSet: Set[Int] = aSet_B
}

new B()

so, the following happens:

  1. Memory for aSet_A and aSet_B is allocated and set to null.
  2. Initializer of A is run.
  3. require on aSet.contains(3) is invoked
  4. Since aSet is overridden in B, it returns aSet_B.
  5. Since aSet_B is null, an NPE is thrown.

To avoid this, you can implement aSet as a lazy variable:

abstract class A { 
  def aSet: Set[Int]
  require(aSet.contains(3)) 
}

class B extends A {
  lazy val aSet = Set(4,5,6) 
}

new B()

This throws the requirement failed exception:

java.lang.IllegalArgumentException: requirement failed

Obligatory link to Scala's FAQ:

  • Why is my abstract or overridden val null?

List of related questions:

  1. Why does implement abstract method using val and call from superclass in val expression return NullPointerException
  2. Overridden value parent code is run but value is not assigned at parent


来源:https://stackoverflow.com/questions/51745845/assertions-in-abstract-superclass-scala-creating-npe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!