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.")

Reply via email to