When I run the code below,
class A(private[this] var i: Int) {
println("i = " + i)
i -= 1
println("After decrement, i = " + i)
override def toString = i.toString
}
object A extends App {
val a = new A(1)
println("a = " + a)
}
I get:
i = 1
After decrement, i = 0
a = 1
If I replace private[this]
by private
, I get the expected behavior, i.e. the last output line becomes a = 0
. I'm using IntelliJ 2016.1.2, Scala plugin version 3.0.6., and scala-sdk-2.11.8.
It's a bug. See SI-6880.
private[this]
on a constructor var causes it to mistakenly shadow itself, and you get the original value instead of the accessor you want.
Yes, it's a bug (SI-6165, SI-6880).
Let's explore further. This is the decompiled code for both cases:
private[this]
:
class A extends Object {
<paramaccessor> private[this] var i: Int = _;
override def toString(): String = scala.Int.box(A.this.i).toString();
def <init>(i: Int): com.yuval.A = {
A.this.i = i;
A.super.<init>();
scala.this.Predef.println("i = ".+(scala.Int.box(i)));
i = i.-(1);
scala.this.Predef.println("After decrement, i = ".+(scala.Int.box(i)));
()
}
};
Here, we see that var i
is created for the object and is accessed directly in the code. We see that i
is assigned to A.this.i
, which is a direct assignment to the field. Later, the mutated value is assigned to i
, the method argument, not to A.this.i
, the field of class A
. The actual value i
is being shadowed.
On the contrary, when i
is private
:
class A extends Object {
<paramaccessor> private[this] var i: Int = _;
<accessor> <paramaccessor> private def i(): Int = A.this.i;
<accessor> <paramaccessor> private def i_=(x$1: Int): Unit = A.this.i = x$1;
override def toString(): String = scala.Int.box(A.this.i()).toString();
def <init>(i: Int): com.yuval.A = {
A.this.i = i;
A.super.<init>();
scala.this.Predef.println("i = ".+(scala.Int.box(A.this.i())));
A.this.i_=(A.this.i().-(1));
scala.this.Predef.println("After decrement, i = ".+(scala.Int.box(A.this.i())));
()
}
};
Here, we see that i
has a getter and setter methods, unlike private[this]
. We also see that the decrement is being done on A.this.i_
, which is the setter for the field member A.this.i
.
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