Possible optimized record construction in order to use as DTO

Brian Goetz brian.goetz at oracle.com
Thu Jan 11 13:37:23 UTC 2024


"Can I specify parameters by name instead of position" is a frequent 
request.  Unfortunately there's a lot more complexity under the 
waterline here than anyone wants to talk about.

The short answer to the localized question ("could we support by-name 
invocation of the canonical record constructor") is "yes"; since the 
component names are committed as part of the classes interface, it is 
relatively simple matter to support this for the canonical constructor 
of records.  But that begs the question: would this be a good idea (let 
alone "would this actually make people happy.")  Let's talk about how 
this glass will seem X% empty.

First, because this is specific to records (and to a specific 
constructor for records), this creates a seam between how you can 
interact with records and with other classes.  That means that users 
have to keep a "mental dictionary" of which classes are records and 
which are not.  Second, because the use site is likely to be in a 
separate compilation unit, you've now created an impediment to migrating 
between records and their equivalent classes, because such a migration 
would no longer be source compatible (clients would fail to recompile).  
Third, people will surely find this boundary to be irregular; "why can I 
do it with this class and not that" or "with this constructor and not 
that" or "with constructors but not with static factories" will be 
frequent questions; even if these questions have good answers, it means 
that we've increased the set of fiddly rules that all developers have to 
internalize.  And developers are rarely made happy by "OK, you can do 
that on tuesday mornings only" solutions; if anything, it creates more 
unhappiness that they can't do it all week long.

And that doesn't mention the elephant in the room: default values.  Most 
of the time, when people ask about by-name invocation, the question of 
defaults for parameters they do not name isn't far behind.  And this is 
where it really gets messy, because this injects new complexity into an 
already-complex area of the language (overload selection), and some 
painful questions about binary compatibility ("surely I can add another 
parameter with a default?")

However, if your record really does have reasonable defaults for some 
fields (such as empty lists, not just null), the proposed `with` 
mechanism would let you do what you want without a new feature: define a 
"minimal constructor" with the required fields (which fills in defaults 
for the others), and then combine that with a reconstruction expression:

     new Foo(reqA, reqB, reqC)
         with { optD = 3, optQ = "Hi Bob" }

and you're good.



On 1/11/2024 7:48 AM, Roel Meeuws wrote:
> Dear all,
>
> This is my first message to this list, so I hope I am not proposing 
> something which has already been discussed before. But here goes.
>
> In several projects at different companies I have seen the use of big 
> bean classes with lots of data inside and getters, setters, toString, 
> equals, hashcode added. In some projects the boilerplate was mitigated 
> with Lombok, but of course recent JDKs provide the notion of Records.
>
> Now records are great data carriers with much less boilerplate, 
> however, there is a particular problem when constructing them for very 
> big sets.
> Consider a dto representing a line in some EU legal obligation report 
> (of which there are many) that may heve hundreds of fields. When 
> constructing such an object there is no idea of what parameter is 
> being filled in in the code that is constructing the object
>
> e.g.
>
> record IrritatinglyBigEUReportLine(
>   long processingId;
> ZonedDateTime reportTime;
> String firstName;
> String lastName;
> String leiCode;
>   String legalReportingId;
> BigDecimal riskAmount;
>   BigDecimal mifidRiskAmount;
>   BigDecimal mifid2FinancialRiskAmount;
>   BigDecimal mifid2SomeOtherAmount;
>   ......
> ) {}
>
> now let's construct this:
> var line = new IrritatinglyBigEUReportLine(
> 12345,
> ZonedDateTime.now(),
> "John",
> "Doe",
> "529900T8BM49AURSDO55",
> BigDecimal.valueOf("100.0"),
> BigDecimal.valueOf("100.0"),
> BigDecimal.valueOf("100.0"),
> BigDecimal.valueOf("100.0"), // anyone knows what this value is here?
>   ...
> );
>
> // also this will give a compile error in my IDE, which parameter is 
> missing now?
>
> Could we introduce a better way of initialization like the following, 
> which is like the `with`-er syntax, I have read Brian Goetz writing about.
> var line = new IrritatingLuBigEUReportLine with {
>   processingId =12345;
>   reportTime = ZonedDateTime.now();
>   firstName = "John";
>   lastName = "Doe";
>   leiCode = "529900T8BM49AURSDO55";
>   legalReportingId = "ERE43434452ERERTTT";
>   riskAmount = BigDecimal.valueOf("100.0");
>   mifidRiskAmount = BigDecimal.valueOf("100.0");
>   mifid2FinancialRiskAmount = BigDecimal.valueOf("100.0");
>   mifid2SomeOtherAmount = BigDecimal.valueOf("100.0");
>   ...
> };
>
> Roel
>
> --------------------------------------------
> Roel Meeuws
> Email: r.j.meeuws at gmail.com
> Mob. phone: +31 (0)6 10 82 44 01
> --------------------------------------------
>
> <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> 
> 	Virus-free.www.avg.com 
> <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> 
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20240111/0c94653f/attachment-0001.htm>


More information about the amber-dev mailing list