Bill
Bill

Reputation: 45465

Inheritance and initialization in Scala

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

Answers (1)

Jean-Philippe Pellet
Jean-Philippe Pellet

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
  • early initialization of 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

Related Questions