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