Reputation: 228
the code goes here:
abstract class Element {
def contents: Array[String]
val height = contents.length
val width = if(height ==0 ) 0 else contents(0).length
override def toString = contents(0)
}
class ArrayElement(override val contents: Array[String]) extends Element
class LineElementT(s: String) extends Element {
override def contents = Array(s)
}
class LineElementF(s: String) extends Element {
override val contents = Array(s)
}
these three sub-classes are OK except the LineElementF
, which throws an NullPointerException
when creating instance with val lef = new LineElementF("Wrong")
Upvotes: 4
Views: 342
Reputation: 26530
The Scala language also has a special syntax (sometimes called early definitions or early initilizer), which allows to execute the constructor of a subclass before the constructor of its superclass:
class LineElementEI(s: String) extends {
override val contents = Array(s)
} with Element
To clarify why regular "late initialization" does not work with your LineElementF
: In the body of the superclass you are trying to evaluate contents.length
, but the body of the subclass is only evaluated after the superclass, so contents
is still null
. You can either solve it be using lazy evaluation on all fields which depend on subclass initialization or change the initialization order as shown above.
Upvotes: 1
Reputation: 8866
This NPE happens at height initialization. At the moment of height initialization val contents of LineElementF is not initialized.
You can avoid this NPE by declaring both height and width as lazy:
lazy val height = contents.length
lazy val width = if(height ==0 ) 0 else contents(0).length
Upvotes: 4