Possible records tweak
Brian Goetz
brian.goetz at oracle.com
Fri Apr 24 18:24:39 UTC 2020
I have been reviewing various Stack Overflow and other queries regarding
the use of records, and in particular the compact constructor.
The compact constructor was intended to support a model where the
constructor body minimally mutates the _constructor arguments_ (if they
need to be normalized, defaulted, or clamped), which are then
automatically committed to the fields on successful exit:
record Rational(int num, int denom) {
Rational {
int gcd = gcd(num, denom);
num /= gcd;
denom /= gcd;
}
}
However, developers do not seem to be getting this, and they are instead
appealing to the old idiom:
record Rational(int num, int denom) {
Rational {
int gcd = gcd(num, denom);
this.num = num / gcd;
this.denom = denom / gcd;
}
}
My concern here is severalfold:
- Mixing the "user initialized" and "auto initialized" idioms is
potentially confusing, as some fields
will be DA at some points in the constructor body, and others
won't. This invites confusion both
for writers and readers.
- There will be "style wars" over which idiom is better; since this is
a new feature and was designed
with a particular idiom in mind, we may simply prefer to enforce
that idiom.
- My intent is to carry this idiom elsewhere into the language, at the
appropriate point in time.
While for records, we have an implicit mapping of ctor args to
fields that enables this auto-
init feature, it may be useful to also allow for an explicit mapping
in non-record cases.
This might look like this (please, let's not design this feature
now, I share this as a
"where we might want to go" thought as it affects the feature
currently on the table):
class Foo(int x, int y) {
int x;
int y;
Foo(int __this.x, int __this.y) { }
}
Here, we are annotating the constructor argument in a way that says "the
name and type correspondence between this constructor argument and the
field of the same name is not accidental, please fill in the boilerplate
for me", and we would get the same auto-init benefit as we do with
compact constructors in records.
(Also (and please, we are not designing this one now either), at some
point we will have declared deconstruction patterns, which may look very
much like "reverse constructors", and will be candidates for the same
"this binding variable corresponds to a field" treatment, with the same
potential for boilerplate elimination.)
So there's room in the future for the user to fill in the "this
similarity is not an accident" and be rewarded with more compact, less
error-prone code just like we do with compact constructors.
So, the question I want to ask is: should we simply _ban_ reads and
writes to `this.x` in the body of a compact constructor, and let the
auto mechanism take care of it, so there is no confusion about mixing
initialization modes, the correct idiom, or reading possibly
uninitialized fields? (If we did, we would probabably extend this to
`this`-bound fields in the future, should that feature come to pass.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20200424/406e6fbb/attachment.htm>
More information about the amber-spec-experts
mailing list