3

If class is not a final one, it may be extended.

There are two possibilities for values: it may be overridden and should be lazy for it, it may not be overridden and should be final.

If val is final - you may assume that all computations over it would work through class hierarchy. If val may be overriden you should declare it lazy for not becoming broken after extending. You may leave val plain and this gives no guaranties it would be extended in right way.

What use cases imply using plain values?


Example of class initialization failure without lazy values

abstract class A {
  lazy val x1 : String = throw new Exception()
  val x2 : String = "mom"
  val x3 : String = x1 + ", " + x2
  println("A: " + x3)
}
class B extends A {
  override lazy val x1: String = "hello"
  println("B: " + x3)
}
class C extends B {
  override val x2: String = "dad"
  println("C: " + x3)
}

testing it:

scala> new B
A: hello, mom
B: hello, mom
res8: B = B@7e2bd615

it works, but further sub-classing broke already existing functionality

scala> new C
A: hello, null
B: hello, null
C: hello, null
res5: C = C@52a53948

setting lazy on x2 fixes the case:

abstract class A {
  lazy val x1 : String = throw new Exception()
  lazy val x2 : String = "mom"
  val x3 : String = x1 + ", " + x2
  println("A: " + x3)
}
class B extends A {
  override lazy val x1: String = "hello"
  println("B: " + x3)
}
class C extends B {
  override lazy val x2: String = "dad"
  println("C: " + x3)
}

right initialization order:

scala> new C
A: hello, dad
B: hello, dad
C: hello, dad
res6: C = C@5e970110
ayvango
  • 5,867
  • 3
  • 34
  • 73

1 Answers1

3

Basically, you are screwing it up.

The problem is not the override, the problem is that you are not paying attention to the order in which things are initialized. There are ways to make it work, and ways to make it not work, and you picked the latter. This works:

scala> class C extends { override val x2: String = "dad" } with B {
     |   println("C: " + x3)
     | }
defined class C

scala> new C
A: hello, dad
B: hello, dad
C: hello, dad
res0: C = C@356e3aaf
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • The problem is there are three ways to extend, one of them is incorrect. And this one breaks encapsulation and makes breaking base class functionality too easy – ayvango Aug 26 '12 at 10:43
  • 2
    @ayvango Inheritance breaks encapsulation. See Effective Java for a discussion, google it, or ask another question if you want more details on that. Everything option discussed above has its use, and it's the programmers responsibility to make sure it works, or just stay away from it. Scala will not forbid things that have use because some programmers might misuse them -- if you want that, Scala might not be the language for you. – Daniel C. Sobral Aug 26 '12 at 15:37
  • I was under impression that scala is declarative but it gave me cold shower this time. And pre-initilizers looks ugly. – ayvango Jul 14 '15 at 00:37
  • @ayvango fwiw, Odersky wants to remove them from the language. – Daniel C. Sobral Jul 16 '15 at 16:45