Records: construction and validation
Brian Goetz
brian.goetz at oracle.com
Mon Mar 12 22:03:21 UTC 2018
> Which leads to a question: if we have a record constructor with no
explicit constructor call, do we do the default initialization at the
beginning or the end?
Thinking some more, I think there's a better (but somewhat surprising)
answer:
In all classes, the compiler inserts a super call if there is no
explicit super/this, and it does so at the beginning. This argues for
putting the implicit initialization at the top, since we already do
something similar elsewhere. But ... this still gets in the way of
normalizing fields of the current class. So, let's refine this answer;
if there is no explicit super/this, we put the implicit *super call* at
the _top_ and the implicit *field initialization* _at the bottom_. So given
abstract record A(int a) { }
record B(int a, int b) extends A(a) { }
then
public B {
if (b <= 0)
throw new IllegalArgumentException("b");
}
is really shorthand for
public B {
super(a); // implicit
if (b <= 0)
throw new IllegalArgumentException("b");
this.b = b; // implicit
}
This preserves consistency with implicit super in other cases, and also
allows explicit code to normalize parameters without additional
ceremony, as in:
B {
if (b < 0) b = 0;
}
Here, the assignment to the parameter b will happen before the implicit
assignment of `this.b = b`, so we get what we expect. And in:
B {
cachedSum = a + b;
}
the receiver is now DA at this point, so this is allowed too. (If you
happen to reference this.b, you'll be told this is DU, so you can't make
a mistake there.) So in almost no circumstances will you need an
explicit default.this(...) call.
More information about the amber-spec-experts
mailing list