蘇哲聖
蘇哲聖

Reputation: 795

Scala override val in constructor

I find a strange result in the following code.

object Practice {
  class A(val seq: Seq[Int]){
    println(f, seq)
    def f: Seq[Int] = seq
  }

  class B(override val seq: collection.mutable.WrappedArray[Int]) extends A(null)

  def main(args: Array[String]): Unit = {
    new B(Array(3,4,2))
  }
}

The print result is "(WrappedArray(3, 4, 2),null)", which means seq and f are different! Why?

Upvotes: 1

Views: 607

Answers (1)

Dima
Dima

Reputation: 40500

The "body" of the scala class is actually the body of the constructor in java. Something like public A(seq: Seq) { this.seq = seq; prinltn(f(), seq); }

This is executed during B's construction, when it calls A(null), and prints the value of the parameter, which is null. The parameter shadows the member.

Try changing the definition of A to something like this:

class A(_seq: Seq[Int]){
  println(f, seq)
  val seq: Seq[Int] = _seq
  def f: Seq[Int] = seq
}  

Now, new B(...) will print two identical values.

The take away from this is - don't override vals. It is almost never necessary, and, as you can see, may be trickier than it looks.

If val is a super-class parameter, you can always just pass the correct value in when constructing the subclass rather than overriding. If it is not a parameter, just make it a def in the superclass.

Upvotes: 3

Related Questions