cfchou
cfchou

Reputation: 1239

Constructor parameter names and class member names

I generally understand how Scala deals with constructor parameters, i.e. generating getter for val and getter/setter for var. I also have found quite a few discussions about name clashes between constructor parameters and class members.

For those names w/o val & var, I expect that if they're prefixed with this., then class members instead should be used. But that's not the case.

class A(val a: Int) {
  def m = println("A.a: " + a)
}

class B(a: Int) extends A(2 * a) {
  override def m = {
    super.m
    println("@a: " + a)
    println("this.a: " + this.a)  // this is @a, not A.a
  }
}

object TestApp extends App {
    val b = new B(10)
    b.m
    println(b.a); // this is A.a
}

Output:

A.a: 20
@a: 10
this.a: 10
20

I feel that it's slightly weird but is there a design reason behind it?

Upvotes: 1

Views: 205

Answers (1)

4lex1v
4lex1v

Reputation: 21557

As you wrote in your question Scala generates a getter for a val, so when you declare a val parameter in you A class, it actually has a method m and a field a, which are inherited by the B class. But you also have an a parameter in you B class, which is doubled and passed as an argument to the super constructor of A. To understand what's going on, turn on option -Xprint:typer for your repo and paste your code, e.g A represented like this:

class A extends scala.AnyRef {
  <paramaccessor> private[this] val a: Int = _;
  <stable> <accessor> <paramaccessor> def a: Int = A.this.a;
  def <init>(a: Int): A = {
    A.super.<init>();
    ()
  };
  def m: Unit = scala.this.Predef.println("A.a: ".+(A.this.a))
}

As you can see Scala created a hidden private[this] field for you a parameter. And here is representation for the B class:

class B extends A {
  <paramaccessor> private[this] val a: Int = _;
  def <init>(a: Int): B = {
    B.super.<init>(2.*(a));
    ()
  };
  override def m: Unit = {
    B.super.m;
    println("@a: ".+(B.this.a));
    println("this.a: ".+(this.a))
  }
}

As you can see Scala also defined private[this] field for your a parameter in the B class. But because you didn't mark it as a val value, it didn't generate new a getter, which is still defined as A.this.a, but not B.this.a, so that's why you r getting 20 when calling b.a.

As an answer, i don't think that there is some complex design behind this, it looks logical and quite reasonable. If you rename your a param in B class constructor and pass it to A, nothing would change.

Upvotes: 2

Related Questions