Draft JEP: Derived Record Creation (Preview)
Brian Goetz
brian.goetz at oracle.com
Wed Jan 24 20:33:34 UTC 2024
> And as a general remarks, I hope there will be a following JEP about record instance creation that allows to use the syntax of a transformation block to initialize a record.
> Because as this have been already discussed on several mailing list, if we only give the derived instance creation syntax, people will twist it to be able to initialize a record by component names, by adding an empty constructor that does nothing on the record. Defeating the idea that constructors should ensure that an invalid instance is not possible to create.
>
Two things about this.
1. In a sense, there _already is_ a way to create a record instance
using the syntax of a transformation block: it is called a compact
constructor. If you look carefully, the body of a compact constructor,
and RHS of a with-expression, are the same thing -- they are blocks for
which N mutable locals magically appear, the block gets run, the final
values of those locals are observed, and fed to the canonical
constructor of a record.
But I know this is not what you mean.
2. You are hoping that this can be turned into something like invoking
constructor parameters by name rather than positionally. But it seems
that your argument here is not "because that would be a really good
thing", but more "people want it so badly that they will distort their
code to do it". But that's never a good reason to add a language feature.
I think many of the "turn records into builders" proposals (of which
there are many) leave out an important consideration: that the real
value of by-name initialization is when you have an aggregate with a
large number of components, most of which are optional. Initializing with
new R(a: 1, b: 2, c: 3)
is not materially better than
new R(1, 2, 3)
when R only has three components. It is when R has 26 components, 24 of
which are optional, that makes things like:
new R(a:1, z :26)
more tempting. But the suggestion above doesn't move us towards having
an answer for that, and having to write out
new R(a: 1, b : <default-for-b>, c: <default-for-c>, ... z: 26)
isn't much of an improvement.
For records for which most parameters _do_ have reasonable defaults,
then a slight modification of the trick you suggest actually works, and
also captures useful semantics in the programming model:
record R(int a /* required */,
int b /* optional, default = 0 */,
...
int z / * required */) {
public R(int a, int z) { this(a, 0, 0, ..., z); }
}
and you can construct an R with
new R(1, 26) with { h = 8 };
where the alternate constructor takes the required parameters and fills
in defaults for the rest, and then you can use withers from there.
(People will complain "but then you are creating a record twice, think
of the cost", to which the rejoinder is "then use a value record.")
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20240124/9b261a5c/attachment.htm>
More information about the amber-spec-experts
mailing list