<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr" data-marker="__DIVIDER__"><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Brian Goetz" <brian.goetz@oracle.com><br><b>To: </b>"Remi Forax" <forax@univ-mlv.fr><br><b>Cc: </b>"Chris Bouchard" <chris@upliftinglemma.net>, "amber-dev" <amber-dev@openjdk.org><br><b>Sent: </b>Friday, March 1, 2024 4:45:58 PM<br><b>Subject: </b>Re: Scope for JEP 468: Derived record creation<br></blockquote></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><font size="4" face="monospace">I would rather revisit "record
literals" when we look more carefully and holistically at
collection literals, which will come later when some other
foundations are in place. The current discussion is mostly one of
those "While you've got the patient under sedation, can we do a
nose job too?", and, just as in medicine, such questions usually
bely some wrong assumptions about where the costs and benefits
lie. </font></blockquote><div><br></div><div>I agree that it's a step after record literals. <br data-mce-bogus="1"></div><div>Does it mean that deconstructor, at least the exact syntax, should also be discussed after record literals ?<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>Rémi</div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br>
<br>
<div class="moz-cite-prefix">On 3/1/2024 10:39 AM, Remi Forax wrote:<br>
</div>
<blockquote cite="mid:846883428.18660307.1709307595144.JavaMail.zimbra@univ-eiffel.fr">
<pre class="moz-quote-pre">----- Original Message -----
</pre>
<blockquote>
<pre class="moz-quote-pre">From: "Brian Goetz" <a class="moz-txt-link-rfc2396E" href="mailto:brian.goetz@oracle.com" target="_blank"><brian.goetz@oracle.com></a>
To: "Chris Bouchard" <a class="moz-txt-link-rfc2396E" href="mailto:chris@upliftinglemma.net" target="_blank"><chris@upliftinglemma.net></a>, "amber-dev" <a class="moz-txt-link-rfc2396E" href="mailto:amber-dev@openjdk.org" target="_blank"><amber-dev@openjdk.org></a>
Sent: Friday, March 1, 2024 3:24:02 PM
Subject: Re: Scope for JEP 468: Derived record creation
</pre>
</blockquote>
<blockquote>
<pre class="moz-quote-pre">I do understand that there are some people who want by-keyword
invocation *so badly* that they are willing to write bad code to gain
the illusion of doing so. Your example is the canonical example:
MyRecord has no good default, but some people will be tempted to expose
(null, null) as the default anyway (instead of rejecting those in the
constructor) just so they can "stick it to the compiler." (Note that
this is fine if MyRecord actually has a reasonable default, which some
records do, or if you create a constructor that accepts the required
components and fills in sane defaults for the rest.)
Put more bluntly, some programmers overvalue superficial syntactic
preferences so badly that they are willing to compromise the safety and
correctness of their code -- and will pat themselves on the back for
their cleverness while they do it.
</pre>
<blockquote>
<pre class="moz-quote-pre">People have been asking for keyword parameters in Java for years. Whether or not
this block syntax is what the language designers would choose for keyword
parameters, I think that if we introduce this feature without some way to
construct new instances it will become the de facto syntax. It's just too
tempting.
</pre>
</blockquote>
<pre class="moz-quote-pre">Oh, I get people want this. And that bad programmers will surely do
this. (And then they'll complain that they can't do it with classes, or
with factories, or that it interferes with compatible migration from
records to classes.) But I don't think we should let their threatened
bad behavior drive language design decisions.
People think they want keyword parameters, but that's not really what
they want -- they just don't realize it yet. What they really want is
keyword parameters *plus being able to omit parameters that have a
default*. These two may sound like almost the same thing, but the
difference in reality is huge. And as someone who has spent more time
thinking about this problem in Java than probably anyone else, I promise
you this is not the triviality it may seem. So our antipathy to named
invocation is not just that it is a "meh" feature; it is that its cost
and benefit are way out of line with each other.
</pre>
</blockquote>
<pre class="moz-quote-pre">Both can be unified if we introduced a weird syntax to declare and use a value record as parameter or return type.
This is a little bit similar to an anonymous class because the value record is scoped to the method but it has a name so javac error messages and binary compatibility are not an issue
record Circle(int x, int y, int radius) {
Circle(Point(int x, int y)) {
this(x, y, 1);
}
}
which is translated to:
record Circle(int x, int y, int radius) {
Circle(Circle$$Point $p) {
int x = $p.x;
int y = $p.y; // or Circle$$Point(int x, int y) = $p;
this(x, y, 1);
}
}
// like an anonymous class, the EnclosingMethod is Circle(Circle$$Point)
value record Circle$$Point(int x, int y) {}
and at use site
new Circle({ x = 3; y = 4; })
we need inference so { x = 3; y = 4; } is equivalent to new Circle$$Point(3, 4).
The exact details are fuzy but as you know, this also solve
- how to write a de-constructor
Point(int x, int y) deconstructor() {
return { x = this.x; y = this.y; };
}
and it makes the syntax looks like the inverse of the constructor syntax
- how to returns multiple values
Div(int quotient, int remainder) div(int value, int divisor) {
return { quotient = value / divisor; remainder = value % divisor; };
}
- and even how to declare tuples, if we allow (3, 4) to be inferred as new Circle$$Point(3, 4) too.
The idea is that a value record is so lighweight at runtime that having a syntax that mix the declaration of the value record and its use make sense.
I also found this idea stupid at first but it keep popping in a lot of use cases.
Rémi
</pre>
<blockquote>
<pre class="moz-quote-pre">
On 2/29/2024 7:39 PM, Chris Bouchard wrote:
</pre>
<blockquote>
<pre class="moz-quote-pre">Hi there. I'm new to this mailing list, but I had a similar thought to Swaranga
recently when this JEP was posted on Reddit.
Personally, my primary concern isn't having nice syntax for constructing
records. It's that if we *don't* provide nice syntax for constructing records,
people will be incentivized to hack it in by overloading the new "with" syntax.
For example, consider something like
record MyRecord(String foo, String bar) {
MyRecord {
// We'd prefer to reject nulls entirely, but we'll allow all nulls
// to have a "blank" object.
if (allNull(foo, bar))
return;
// With that out of the way, validate our *actual* constraints.
if (anyNull(foo, bar) || foo.length < 1 || bar.length < 1)
throw MyDomainException();
}
public static MyRecord blank() {
return MyRecord(null, null);
}
}
Now I can say
var value = MyRecord.blank() with {
bar = "World";
foo = greeting(bar);
};
Except that now, because my model didn't have a natural "blank" value, I've
added an *un*natural one in the interest of ergonomics. This "blank" object has
to be a valid record value. And since the with block's variables are all
initialized to null, users can accidentally run into problems with partial
initialization.
var value = MyRecord.blank() with {
// Whoops, forgot to initialize bar so it's still null.
// bar = "World";
foo = greeting(bar); // NPE
}
On the other hand, if we provided an actual way to initialize a fresh record
using this block syntax, we could say that all variables in the block are
unitialized to start and must be assigned before use. And this initial state
wouldn't have to be accepted by the constructor.
People have been asking for keyword parameters in Java for years. Whether or not
this block syntax is what the language designers would choose for keyword
parameters, I think that if we introduce this feature without some way to
construct new instances it will become the de facto syntax. It's just too
tempting.
Thanks for your time and attention,
Chris Bouchard
On Thu Feb 29 23:11:32 UTC 2024, Brian Goetz wrote:
</pre>
<blockquote>
<pre class="moz-quote-pre">While such a feature is possible, I am not particularly excited about it
for several reasons. If the goal is "I want to construct using named
instead of position arguments" (which I think is your goal), it's a
pretty verbose syntax; a better one would be
new R(a: 1, b: 2)
But that's a much smaller concern. The bigger one is that I don't think
the language is improved by having a named parameter mechanism for
records, but for nothing else (not for instantiating class instances,
not for invoking methods.) While it might seem "better than nothing",
having two different ways to do something, but one of them only works in
narrow situations, is as likely to be frustrating than beneficial. If
the payoff is big enough, then it might be a possibility, but
"invocation by parameter name" is nowhere near that bar.
Finally, if it works for records but not for classes, it makes it harder
to refactor from records to classes, since there will be use sites that
have to be adjusted.
So I think for the time being, the answer is "no", though if we run out
of things to work on, we might reconsider.
On 2/29/2024 4:34 PM, Swaranga Sarma wrote:
</pre>
<blockquote>
<pre class="moz-quote-pre">The JEP looks really promising. However I am wondering if there will
be a separate JEP for creating new records from scratch with similar
syntax.
The current JEP states that its goals are to enable creating records
from an existing record and for that it seems sufficient. But I would
also love to be able to create new records from scratch using the same
syntax. Something like:
var circle = new Circle with {
radius = 0.5f;
center = new Center with {
x = 0;
y = -1;
z = 8;
};
};
Originally I had asked Brian Goetz about record literals and they
seemed like a possibility but withers seem like a more general feature
so I am hoping something like this would be supported in the future.
Regards
Swaranga Sarma
</pre>
</blockquote>
</blockquote>
</blockquote>
</blockquote>
</blockquote>
<br><br></blockquote></div></div></body></html>