Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding method as the field in Scala

Tags:

scala

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?

like image 748
Volodymyr Avatar asked Dec 12 '22 19:12

Volodymyr


2 Answers

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).

like image 69
Travis Brown Avatar answered Jan 02 '23 15:01

Travis Brown


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.

like image 39
Aaron Novstrup Avatar answered Jan 02 '23 14:01

Aaron Novstrup