Reputation: 63062
Let us define simplest inheritance:
class A { val base: String = { println("a hello"); "hello" } }
class B extends A { override val base: String = { println("b hi"); "B hello"} }
Now let's try it out:
scala> new B().base
a hello
b hi
res0: String = B hello
So .. many (/most?) of you out there will likely not be surprised by this. I was . It had been my (incorrect ..) assumption that the B.base
would completely override A.base
. Instead we see both* methods being invoked : the base method A.base
then the overriding method B.base
.
Ok then .. so is it true that in order to avoid this doubling-up behavior that the val
must be converted to a def
(method) ?
class A { def base: String = { println("a hello"); "hello" } }
class B extends A { override def base: String = { println("b hi"); "B hello"} }
And now we have the desired behavior:
scala> new B().base
b hi
res1: String = B hello
Given this situation: when is overriding val
useful within the body of a class?
Upvotes: 1
Views: 64
Reputation: 170733
It had been my (incorrect ..) assumption that the B.base would completely override A.base . Instead we see both methods being invoked : the base method A.base then the overriding method B.base.
No, we don't. The println
calls in both A.base
and B.base
happen in the constructor, not when you access base
. This is just what (non-lazy
) member val
means: the right-hand side is executed in the constructor and the result (just "hello"
or "B hello"
in your case) is stored into a field. Accessing base
just returns the value of that field.
And superclass constructor is always fully executed before the subclass constructor, there's no way to override it (you can override any methods it invokes, but you need to be careful so they don't rely on subclass' state which isn't initialized yet).
scala> val b = new B()
a hello
b hi
scala> b.base
res0: String = B hello
when is overriding val useful within the body of a class?
When you want the subclass' val
to have a different value, of course.
Upvotes: 1
Reputation: 63062
LAZY val
It came to me ..
class A { lazy val base: String = { println("a hello"); "hello" } }
class B extends A { override lazy val base: String = { println("b hi"); "B hello"} }
And now we get expected behavior:
scala> new B().base
b hi
res1: String = B hello
Upvotes: 0