"With" for records
Brian Goetz
brian.goetz at oracle.com
Fri Jun 10 12:44:51 UTC 2022
In
https://github.com/openjdk/amber-docs/blob/master/eg-drafts/reconstruction-records-and-classes.md
we explore a generalized mechanism for `with` expressions, such as:
Point shadowPos = shape.position() with { x = 0 }
The document evaluates a general mechanism involving matched pairs of
constructors (or factories) and deconstruction patterns, which is still
several steps out, but we can take this step now with records, because
records have all the characteristics (significant names, canonical ctor
and dtor) that are needed. The main reason we might wait is if there
are uncertainties in the broader target.
Our C# friends have already gone here, in a way that fits into C#, using
properties (which makes sense, as their language is built on that):
object with { property-assignments }
The C# interpretation is that the RHS of this expression is a sort of
"DSL", which permits property assignment but nothing else. This is
cute, but I think we can do better.
In our version, the RHS is an arbitrary block of Java code; you can use
loops, assignments, exceptions, etc. The only thing that makes it
"special" is that that the components of the operand are lifted into
mutable locals on the RHS. So inside the RHS when the operand is a
Point, there are fresh mutable locals `x` and `y` which are initialized
with the X and Y values of the operand. Their values are committed at
the end of the block using the canonical constructor.
This should remind people of the *compact constructor* in a record; the
body is allowed to freely mutate the special variables (who also don't
have obvious declarations), and their terminal values determine the
state of the record.
Just as we were able to do record patterns without having full-blown
deconstructors, we can do with expressions on records as well, because
(a) we still have a canonical ctor, (b) we have accessors, and (c) we
know the names of the components.
Obviously when we get value types, we'll want classes to be able to
expose (or not) such a mechanism (both for internal or external use).
#### Digression: builders
As a bonus, I think `with` offers us a better path to getting rid of
builders than the (problematic) one everyone asks for (default values on
constructor parameters.) Consider the case of a record with many
components, all of which are optional:
record Config(int a,
int b,
int c,
...
int z) {
}
Obviously, no one wants to call the canonical constructor with 26
values. The standard workaround is a builder, but that's a lot of
ceremony. The `with` mechanism gives us a way out:
record Config(int a,
int b,
int c,
...
int z) {
private Config() {
this(0, 0, 0, ... 0);
}
public static Config BUILDER = new Config();
}
Now we can just say
Config c = Config.BUILDER with { c = 3; q = 45; }
The constant isn't even necessary; we can just open up the constructor.
And if there are some required args, the constructor can expose them
too. Suppose a and b are required, but c..z are optional. Then:
record Config(int a,
int b,
int c,
...
int z) {
public Config(int a, int b) {
this(a, b, 0, ... 0);
}
}
Config c = new Config(1, 2) with { c = 3; q = 45; }
In this way, the record acts as its own builder.
(As an added bonus, the default values do not suffer from the "brittle
constant" problem that a default value would likely suffer from, because
they are an implementation detail of the constructor, not an exposed
part of the API.)
I think it is reasonable at this point to take this idea off the shelf
and work towards delivering this for records, while we're building out
the machinery needed to deliver this for general classes. It has no
remaining dependencies and is immediately useful for records.
(As usual, please hold comments on small details until everyone has had
a chance to comment on the general direction.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20220610/15807a1b/attachment.htm>
More information about the amber-spec-experts
mailing list