6

Consider the following (simplified) example:

abstract class Bar[T] {
    val f: PartialFunction[T, T]
    val default: PartialFunction[T, T] = { case x => x }
    val chained = f orElse default
}

class Foo extends Bar[Int] {
    val f: PartialFunction[Int, Int] = { case 1 => 2 }
}

And watch it crash:

scala> val foo = new Foo
java.lang.NullPointerException
        at Bar.<init>(<console>:8)
        at Foo.<init>(<console>:6)
        at .<init>(<console>:7)
        at .<clinit>(<console>)
        at RequestResult$.<init>(<console>:9)
        at RequestResult$.<clinit>(<console>)
        at RequestResult$scala_repl_result(<console>)
        ....

However, if we put chained in the concrete class:

abstract class Bar[T] {
    val f: PartialFunction[T, T]
    val default: PartialFunction[T, T] = { case x => x }
}

class Foo extends Bar[Int] {
    val f: PartialFunction[Int, Int] = { case 1 => 2 }
    val chained = f orElse default
}

It works as expected:

scala> val foo = new Foo
foo: Foo = Foo@16132c4

I have to admit I have absolutely no idea what is happening here. Bug? (This is on Scala 2.8.1.)

Knut Arne Vedaa
  • 15,372
  • 11
  • 48
  • 59
  • See this question for a solution/workaround: http://stackoverflow.com/questions/4712468/in-scala-what-is-an-early-initializer – Raphael Jan 18 '11 at 09:30

2 Answers2

5

"Why is my abstract or overriden val null?" https://github.com/paulp/scala-faq/wiki/Initialization-Order

retronym
  • 54,768
  • 12
  • 155
  • 168
0

My guess: This is an optimization done at compile time. The compiler recognizes that you override f in Bar. Therefore, the "constructor" of Bar executes first the stuff from Foo -- sans f! -- and then the stuff in the definition of Bar. Therefore, f is not defined when chained is constructed.

I call bug.

Raphael
  • 9,779
  • 5
  • 63
  • 94