From brian.goetz at oracle.com Thu Dec 11 16:01:13 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 11 Dec 2025 11:01:13 -0500 Subject: Fwd: An improvement request on records In-Reply-To: <9fb7ea1a-1e4d-4294-bd7f-3aeb8a7ab1ce@kai-hofmann.de> References: <9fb7ea1a-1e4d-4294-bd7f-3aeb8a7ab1ce@kai-hofmann.de> Message-ID: The below was received on amber-spec-comments. The author makes a renewed plea for final, non-component fields in records. This point was discussed extensively during the design of records, so I won't recapitulate the discussion here. -------- Forwarded Message -------- Subject: An improvement request on records Date: Thu, 11 Dec 2025 15:27:28 +0100 From: Kai Hofmann To: amber-spec-comments at openjdk.org To whom it may concern, I am working here since some years on my OpenSource projects, and until now I had never a reason to made comments on Java - but now I feel I have to raise my voice on records: Since some years I developed a library of DDD valueObjects both as normal Java objects and also in a parallel branch as records. At the moment you can find this work here: https://github.com/PowerStat/Validation But I plan to rename this project, because in the meantime the project name is no longer a good choice - maybe it will name something like ValueObjectLibrary - you will find it under my github repos. So from my experiences I can say it is a correct design decision to not have instance fields within records. But in my opinion this thought is to simple, because private "final" instance fields should be possible and will be useful and could safe duplicated code as well as runtime! So the point is that final instance fields have to be initialized within the constructor and will be unchangeable after a record has been constructed - so they are harmless! As an example I have implemented a MACAddress class/record that represents a hardware mac address. Within the normal class implementation I split the mac address into it's parts only once within the construtor, later on I have multiple methods that work on this split parts. But within a record this is not possible so I have to do the split within every method where I need it - thats waste of code and runtime! Another example is my implementation of the ISBN13 - see https://en.wikipedia.org/wiki/ISBN These numbers could come with 2 different formats: with or without separator chars in it - both formats are equal. So in my class implementation I would do a normalization (without separators) and store this one internally. Within a record this normalization in the construtor is not possible, because I could not have instance fields nor could I change the records parameter within the constructor because its already fixed :( So ISBN13 could not be implemented as a record! I vote for extending the record specification to have private "final" instances within it and maybe to allow to manipulate the construction parameters within the constructor. Would be nice to hear from you about this. Greetings and have a nice Christmas and a Happy New Year. PowerStat (Kai Hofmann) -------------- next part -------------- An HTML attachment was scrubbed... URL: From amaembo at gmail.com Thu Dec 11 16:33:09 2025 From: amaembo at gmail.com (Tagir Valeev) Date: Thu, 11 Dec 2025 17:33:09 +0100 Subject: An improvement request on records In-Reply-To: References: <9fb7ea1a-1e4d-4294-bd7f-3aeb8a7ab1ce@kai-hofmann.de> Message-ID: Hello! Well, as you have reposted this, I assume that you are not against some discussion on the topic. The both use-cases mentioned by Kai Hofmann are about caching some intermediate computation derived from the record fields to improve the performance of the application (they are not strictly necessary for correctness). In his case, such cached values are computed in the constructor, which is somewhat unusual for (presumably heavy) computation. What if we only use the methods that never access these cached values? In this case, the computation will be just a waste of CPU time. Usually, people perform heavy computations on demand, deferring the computation until it's actually necessary (e.g., String.hash field). Now, we have a perfect construct for this: LazyConstant. So I may imagine enhanced records with a new feature: - private final fields in records are allowed only if their type is LazyConstant - such fields must have an initializer like LazyConstant.of(() -> lambda) - the initializer is guaranteed to see the record components. So we cannot use such fields in constructor prolog (or in compact constructor), before all the components are assigned - it's assumed (though not statically checked) that such fields depend on record components only. They are always transient and not initialized after deserialization. We may also devise some kind of syntactic sugar for LazyConstant fields (not only in records!). E.g. declare them like `private lazy T cached = initializer;` instead of `private final LazyConstant cached = LazyConstant.of(() -> initializer);`. Having an ability to declare such fields will simplify the record specification: we can simply allow fields with 'lazy' modifier (which always implies 'final') without saying anything about type. I'm not saying that it's something that we should do right now, especially taking into account that LazyConstants are still in preview. But probably something useful here could be done in the future. With best regards, Tagir Valeev On Thu, Dec 11, 2025 at 5:01?PM Brian Goetz wrote: > The below was received on amber-spec-comments. > > The author makes a renewed plea for final, non-component fields in > records. > > This point was discussed extensively during the design of records, so I > won't recapitulate the discussion here. > > > -------- Forwarded Message -------- > Subject: An improvement request on records > Date: Thu, 11 Dec 2025 15:27:28 +0100 > From: Kai Hofmann > To: amber-spec-comments at openjdk.org > > To whom it may concern, > > I am working here since some years on my OpenSource projects, and until > now I had never a reason to made comments on Java - but now I feel I have > to raise my voice on records: > > > Since some years I developed a library of DDD valueObjects both as normal > Java objects and also in a parallel branch as records. At the moment you > can find this work here: > > https://github.com/PowerStat/Validation > > But I plan to rename this project, because in the meantime the project > name is no longer a good choice - maybe it will name something like > ValueObjectLibrary - you will find it under my github repos. > > > So from my experiences I can say it is a correct design decision to not > have instance fields within records. > > But in my opinion this thought is to simple, because private "final" > instance fields should be possible and will be useful and could safe > duplicated code as well as runtime! > > So the point is that final instance fields have to be initialized within > the constructor and will be unchangeable after a record has been > constructed - so they are harmless! > > As an example I have implemented a MACAddress class/record that represents > a hardware mac address. > > Within the normal class implementation I split the mac address into it's > parts only once within the construtor, later on I have multiple methods > that work on this split parts. > > But within a record this is not possible so I have to do the split within > every method where I need it - thats waste of code and runtime! > > Another example is my implementation of the ISBN13 - see > https://en.wikipedia.org/wiki/ISBN > > These numbers could come with 2 different formats: with or without > separator chars in it - both formats are equal. > > So in my class implementation I would do a normalization (without > separators) and store this one internally. > > Within a record this normalization in the construtor is not possible, > because I could not have instance fields nor could I change the records > parameter within the constructor because its already fixed :( > > So ISBN13 could not be implemented as a record! > > I vote for extending the record specification to have private "final" > instances within it and maybe to allow to manipulate the construction > parameters within the constructor. > > Would be nice to hear from you about this. > > > Greetings and have a nice Christmas and a Happy New Year. > > > PowerStat (Kai Hofmann) > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Dec 11 16:47:29 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 11 Dec 2025 11:47:29 -0500 Subject: An improvement request on records In-Reply-To: References: <9fb7ea1a-1e4d-4294-bd7f-3aeb8a7ab1ce@kai-hofmann.de> Message-ID: <28aaa90e-b5b6-49e2-8b19-19db22be6860@oracle.com> > Well, as you have reposted this, I assume that you are not against > some discussion on the topic. > > The both use-cases mentioned by Kai Hofmann are about caching some > intermediate computation derived from the record fields to improve the > performance of the application (they are not strictly necessary for > correctness). > In his case, such cached values are computed in the constructor, which > is somewhat unusual for (presumably heavy) computation. What if we > only use the methods that never access these cached values? In this > case, the computation will be just a waste of CPU time. The reason that is always cited for this feature request is "but what about immutable state that is wholly derived from the components" (basically, a cache.)? And yes, this _is_ in the spirit of "the state, the whole state, and nothing but the state"! Unfortunately, the _proposed solution_ "let us declare off-label final fields" is the same thing as "give us the ability to cache data derived from the components."? As an example: ? ? record Listy(int x) { ? ? ? ? private final List impl = new ArrayList<>(); ? ? ? ? public void add(String s) { impl.add(s); } ? ? ? ? public boolean contains(String s) { return impl.contains(s); } ? ? ? ? ... ? ? } Is this a record wrapping one int, or a List implementation with some free accessors and an incorrect implementation of equals/hashCode? tl;dr: the _feature_ that he wants -- derived cached state -- is reasonable.? The _solution_ that is proposed -- is not that.? A more targeted feature would be required. Is making the field a LazyConstant sufficient to bring the "solution" in line with the problem?? Maybe.? But really, this feels more like a language feature for "cached method" or similar.? We've discussed this in the past but its pretty clear that given the scope of such an exploration, it should not be at the top of the list. > Usually, people perform heavy computations on demand, deferring the > computation until it's actually necessary (e.g., String.hash field). > Now, we have a perfect construct for this: LazyConstant. So I may > imagine enhanced records with a new feature: > > - private final fields in records are allowed only if their type is > LazyConstant > - such fields must have an initializer like LazyConstant.of(() -> lambda) > - the initializer is guaranteed to see the record components. So we > cannot use such fields in constructor prolog (or in compact > constructor), before all the components are assigned > - it's assumed (though not statically checked) that such fields depend > on record components only. They are always transient and not > initialized after deserialization. > > We may also devise some kind of syntactic sugar for LazyConstant > fields (not only in records!). E.g. declare them like `private lazy T > cached = initializer;` instead of `private final LazyConstant > cached = LazyConstant.of(() -> initializer);`. Having an ability to > declare such fields will simplify the record specification: we can > simply allow fields with 'lazy' modifier (which always implies > 'final') without saying anything about type. > > I'm not saying that it's something that we should do right now, > especially taking into account that LazyConstants are still in > preview. But probably something useful here could be done in the future. > > With best regards, > Tagir Valeev > > On Thu, Dec 11, 2025 at 5:01?PM Brian Goetz > wrote: > > The below was received on amber-spec-comments. > > The author makes a renewed plea for final, non-component fields in > records. > > This point was discussed extensively during the design of records, > so I won't recapitulate the discussion here. > > > -------- Forwarded Message -------- > Subject: An improvement request on records > Date: Thu, 11 Dec 2025 15:27:28 +0100 > From: Kai Hofmann > To: amber-spec-comments at openjdk.org > > > > To whom it may concern, > > I am working here since some years on my OpenSource projects, and > until now I had never a reason to made comments on Java - but now > I feel I have to raise my voice on records: > > > Since some years I developed a library of DDD valueObjects both as > normal Java objects and also in a parallel branch as records. At > the moment you can find this work here: > > https://github.com/PowerStat/Validation > > > But I plan to rename this project, because in the meantime the > project name is no longer a good choice - maybe it will name > something like ValueObjectLibrary - you will find it under my > github repos. > > > So from my experiences I can say it is a correct design decision > to not have instance fields within records. > > But in my opinion this thought is to simple, because private > "final" instance fields should be possible and will be useful and > could safe duplicated code as well as runtime! > > So the point is that final instance fields have to be initialized > within the constructor and will be unchangeable after a record has > been constructed - so they are harmless! > > As an example I have implemented a MACAddress class/record that > represents a hardware mac address. > > Within the normal class implementation I split the mac address > into it's parts only once within the construtor, later on I have > multiple methods that work on this split parts. > > But within a record this is not possible so I have to do the split > within every method where I need it - thats waste of code and runtime! > > Another example is my implementation of the ISBN13 - see > https://en.wikipedia.org/wiki/ISBN > > > These numbers could come with 2 different formats: with or without > separator chars in it - both formats are equal. > > So in my class implementation I would do a normalization (without > separators) and store this one internally. > > Within a record this normalization in the construtor is not > possible, because I could not have instance fields nor could I > change the records parameter within the constructor because its > already fixed :( > > So ISBN13 could not be implemented as a record! > > I vote for extending the record specification to have private > "final" instances within it and maybe to allow to manipulate the > construction parameters within the constructor. > > Would be nice to hear from you about this. > > > Greetings and have a nice Christmas and a Happy New Year. > > > PowerStat (Kai Hofmann) > > -------------- next part -------------- An HTML attachment was scrubbed... URL: