Another syntax for Java records

Brian Goetz brian.goetz at oracle.com
Tue Nov 22 21:41:34 UTC 2022


To answer your question, we have to go back to "what were we trying to 
accomplish with records in the first place."  The obvious-but-wrong 
answer is "to free Java developers of the tyranny of boilerplate."  
That's an important benefit, but that's a consequence, not the main 
goal, of the records design.

Another way to say this is that records are not just about "make me the 
implementation of the data-carrying class that I want"; they are not an 
"implementation generator" like Lombok or Joda Beans or Immutables or 
AutoValue.  Yes, they do some implementation lifting, but they also make 
promises to clients as well.

The list of components in the record header -- the state description -- 
is used to imply a contract:
  - the class has a constructor whose argument list matches exactly the 
state description
  - the class has a deconstruction pattern whose binding list matches 
exactly the state description
  - the class has accessors for every component in the state description
  - the class has an equals/hashCode/toString derived from the state 
description
  - the class adheres to a contract that couples the constructor, 
accessors, and equals method, which says that if you take apart a record 
with the accessors, and feed the results back to the constructor, you 
get back an equivalent (according to equals) record.

All of these are derived from the state description, and can be counted 
on by clients.  That is why the state description is part of the record 
declaration, not just implied by the fields. (It is also what lets us 
derive a stronger serialization protocol for records, and in the future, 
`with` expressions.)

This is an example of "get the semantics right and the syntax takes care 
of itself."  Records have semantics that permits us to boil away the 
syntax, not the other way around.

If that's not enough, here's a less philosophical answer why your 
approach would be dangerous.  If you could declare

     record R {
         String r;
         int x;
     }

then the implied constructor would take a String and an int. But we are 
used to being able to freely reorder field and method declarations; this 
has always been a source-, binary-, and behavior-compatible change.  But 
in your model, reordering fields would reorder the parameters of the 
constructor, breaking clients (sometimes silently, if you have a record 
whose fields are all the same type.)

On 11/22/2022 4:25 PM, Heinzl, Steffen wrote:
>
> Hi!
>
> I wanted to suggest (if not yet done) to another syntax to Java records.
>
> I don’t quite understand the idea behind the syntax except that some 
> other programming languages do it similar.
>
> A Java class looks like this:
>
> public class MyClass
>
> {
>
>   String s;
>
>   void myMethod(String a, int b);
>
> }
>
> An interface looks like this:
>
> public interface MyInterface
>
> {
>
>   void myMethod(String c, String d);
>
> }
>
> Why all of a sudden is it a good idea to change that syntax to:
>
> public record MyRecord(String r, int x)
>
> {
>
> }
>
> instead of the following syntax (which is also possible in C# by the way)
>
> public record MyRecord
>
> {
>
>   String r;
>
>   int x;
>
> }
>
> I’m teaching Java and I find it strange from a lecturer’s point of 
> view to explain the rationale for introducing the syntax like that. 
> I’d be glad if someone could enlighten me!
>
> Thanks! Best,
>
> Steffen
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20221122/5b490757/attachment-0001.htm>


More information about the amber-dev mailing list