> From: "Dan Heidinga" <[email protected]> > To: "Remi Forax" <[email protected]>, "Brian Goetz" <[email protected]> > Cc: "Gavin Bierman" <[email protected]>, "amber-spec-experts" > <[email protected]> > 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 <[email protected]> on behalf of > [email protected] <[email protected]> > Sent: January 24, 2024 4:43 PM > To: Brian Goetz <[email protected]> > Cc: Gavin Bierman <[email protected]>; amber-spec-experts > <[email protected]> > Subject: Re: Draft JEP: Derived Record Creation (Preview) >> From: "Brian Goetz" <[email protected]> >> To: "Remi Forax" <[email protected]>, "Gavin Bierman" >> <[email protected]> >> Cc: "amber-spec-experts" <[email protected]> >> 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.
