Draft JEP: Derived Record Creation (Preview)
forax at univ-mlv.fr
forax at univ-mlv.fr
Thu Jan 25 09:36:33 UTC 2024
> From: "Dan Heidinga" <dan.heidinga at oracle.com>
> To: "Remi Forax" <forax at univ-mlv.fr>, "Brian Goetz" <brian.goetz at oracle.com>
> Cc: "Gavin Bierman" <gavin.bierman at oracle.com>, "amber-spec-experts"
> <amber-spec-experts at openjdk.org>
> Sent: Thursday, January 25, 2024 2:56:54 AM
> Subject: Re: Draft JEP: Derived Record Creation (Preview)
> Remi, is the issue that this design doesn't address 100% of the use cases you
> think should be addressed?
I think it's a little worst because people will use that design for something not attended and by that will weaken the concept of records.
> With expressions provide a way to express clone-but-update-these-fields without
> requiring the user to manually code the update methods. It's a great tradeoff
> to get more expressiveness. The fact that it's not named parameters isn't a
> draw back of the design.
I agree. The problem i see is that users will use it to have named parameters anyway.
> Additionally, I think there's some confusion about what a with expression does.
> You say "the main way it is used teach people to avoid precondtions in record
> constructor" but it doesn't avoid preconditions... The canonical constructor is
> still called.
It does practically, but I've poorly explained the steps that lead to that conclusion.
Let say I have a record Person with a name and an age, the constructor should check if the name is not null and if the age is positive, but if this record is used has a way to have named parameters, it also needs an empty constructor and because record constructors must delegate to the canonical constructor, the preconditions will be removed.
> --Dan
Rémi
> From: amber-spec-experts <amber-spec-experts-retn at openjdk.org> on behalf of
> forax at univ-mlv.fr <forax at univ-mlv.fr>
> Sent: January 24, 2024 4:43 PM
> To: Brian Goetz <brian.goetz at oracle.com>
> Cc: Gavin Bierman <gavin.bierman at oracle.com>; amber-spec-experts
> <amber-spec-experts at openjdk.org>
> Subject: Re: Draft JEP: Derived Record Creation (Preview)
>> From: "Brian Goetz" <brian.goetz at oracle.com>
>> To: "Remi Forax" <forax at univ-mlv.fr>, "Gavin Bierman" <gavin.bierman at oracle.com>
>> Cc: "amber-spec-experts" <amber-spec-experts at openjdk.org>
>> Sent: Wednesday, January 24, 2024 9:33:34 PM
>> Subject: Re: Draft JEP: Derived Record Creation (Preview)
>>> 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 agree, but it may be a reasonable reason to *not* introduce a feature if the
> main way it is used teach people to avoid precondtions in record constructor.
> I do not hope anything, i'm not ones that write a record with a dozen fields for
> a living. But seeing how far people (and my students) are willing to go to have
> classes initialized by names, i.e. write a full builder class per record, add a
> dependency on an annotation processor like record-builder or lombok, etc, it's
> easy too see how this feature will be abused.
> Data classes usually:
> - can have a lot of components,
> - are updated because business requirement changes modify the data,
> - are application specific, so unlike methods of the JDK/libraries, it's hard to
> remember them.
> so having a way to create them by spelling each component by name is actually a
> good way to make the code readable.
> That's why people goes to a great length to use named parameters.
> And for the anecdote, a recurrent question of my students with a C background is
> to ask how to initialize a class with the field names like C 99 (*).
>> 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.")
> It is nice but in a way it does not solve the problem fully because people may
> still want to initialize the required parameters of R with named parameters.
> Rémi
> (*) The same way my students with a Python background (all my student nowadays,
> because in France, Python is now mandatory in highschool) ask how to create a
> tuple in Java.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20240125/c6b5c532/attachment-0001.htm>
More information about the amber-spec-experts
mailing list