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