I don't understand. Why does Scala support override method as field:
abstract class A {
def i: Int;
}
class B extends A {
val i = 123;
}
val obj:A = new B();
println(obj.i)
Method i
is as field i
. Why?
One quick way to see what's going on here is to compile this code and use javap
to inspect the resulting classes. Here we get the following for A
:
public abstract class A implements scala.ScalaObject {
public abstract int i();
public A();
}
And for B
(with -p
, so we see any private members):
public class B extends A implements scala.ScalaObject {
private final int i;
public int i();
public B();
}
So the val
just ends up as a private field with a getter—much like what you'd write in idiomatic Java, although the naming convention is different (and isn't really a convention, since the compiler handles it for you).
Travis' answer explains how, at the implementation level, some methods can be overridden by a field in Scala but not why. The answer to the why question is related to two programming language design principles: the Uniform Access Principle and the Liskov Substitution Principle.
The Uniform Access Principle essentially says that callers shouldn't have to distinguish between reading a property through a method and reading it through a field -- both calls should look the same and should not betray whether they involve storage or computation.
The Liskov Substitution Principle essentially says that a subtype must honor all the contracts of its parent type. A subtype is allowed to honor stronger contracts than its parent type, but it must not violate any of its parent's contracts.
In Scala, declaring a def
without a parameter list implies a certain contract. Namely, it implies that accessing the associated property will return a value of the declared type. Since referential transparency is not guaranteed, subsequent accesses may or may not return the same value.
Clearly, a val
satisfies the same contract. However, a val
makes an even stronger guarantee: every access will result in the same value. Since this is a stronger contract, it's perfectly consistent with the Liskov Substitution Principle for a subtype to use a val
to implement a def
. Along the same lines, it's prohibited for a subtype to use a def
to implement a val
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With