Reputation: 45465
I have two Scala classes that look like this (paraphrased):
abstract class GenericParser[T] {
val lineFilter : String => Boolean
parseData()
def parseData() : T {
for( line <- .... if lineFilter(line) )
// do things
}
}
class SalesParser extends GenericParser[SalesRow] {
val lineFilter = line => !line.startsWith("//")
// ....
}
The problem is that lineFilter
is null
in parseData
, presumably because parseData
is called while the primary GenericParser
constructor is still running, so the subclass hasn't fully initialized its members.
I can work around this by making lineFilter a def
instead of a val
, but is this expected behavior? It doesn't seem right that this problem should only become apparent after getting an NPE at runtime.
Upvotes: 2
Views: 718
Reputation: 60006
It is indeed the expected behavior, and is exactly the same problem as in this question:
Scala 2.8: how to initialize child class
You can basically copy-paste the answer form that question. Solutions include:
def
or lazy val
instead of val
lineFilter
redesign of your classes to avoid the “virtual method call from superclass's constructor which accesses uninitialized subclass values” problem. For instance, why would you want to store the filter function in a val or return in from a def, while it could be implemented as a method?
abstract class GenericParser[T] {
def lineFilter(line: String): Boolean
parseData()
def parseData() : T {
for( line <- .... if lineFilter(line) )
// do things
}
}
class SalesParser extends GenericParser[SalesRow] {
def lineFilter(line: String) = !line.startsWith("//")
}
Upvotes: 6