<div dir="ltr"><div class="gmail_default" style="font-family:monospace">Hello Rémi,<br><br>Thank you for your response!<br><br>> If you really really want to do it, you can use the<br>> bootstrap method in java.lang.runtime.ObjectsMethods but<br>> it's ugly.<br><br>That's actually way better than I thought it would be. It's surprisingly direct too.<br><br>> We also do not want to close the door to supporting<br>> super.x() if at some point in the future if the VM spec<br>> is changed to introduce a way to generate bridge methods<br>> at runtime.<br>> <br>> The record methods toString/equals/hashCode will be<br>> declare as abstract bridge method in that case.<br><br>I brushed up on bridge methods for this response - <a href="https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html">https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html</a><br><br>I get the concept, but I am curious what having that at runtime would give us that we don't already get at compile time. I don't quite see it.<br><br>Thank you for your time and help!<br>David Alayachew<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Sep 21, 2023 at 1:49 PM Remi Forax <<a href="mailto:forax@univ-mlv.fr">forax@univ-mlv.fr</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div style="font-family:arial,helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)"><div><br></div><div><br></div><hr id="m_-1013115352825319821zwchr"><div><blockquote style="border-left:2px solid rgb(16,16,255);margin-left:5px;padding-left:5px;color:rgb(0,0,0);font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><b>From: </b>"Brian Goetz" <<a href="mailto:brian.goetz@oracle.com" target="_blank">brian.goetz@oracle.com</a>><br><b>To: </b>"David Alayachew" <<a href="mailto:davidalayachew@gmail.com" target="_blank">davidalayachew@gmail.com</a>>, "amber-dev" <<a href="mailto:amber-dev@openjdk.org" target="_blank">amber-dev@openjdk.org</a>><br><b>Sent: </b>Thursday, September 21, 2023 7:18:13 PM<br><b>Subject: </b>Re: Question about records and overriding their "magic methods"<br></blockquote></div><div><blockquote style="border-left:2px solid rgb(16,16,255);margin-left:5px;padding-left:5px;color:rgb(0,0,0);font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><span style="font-size:large"><span style="font-family:monospace">We explored this topic somewhat when designing the feature.  <br><br>When you override a method x, you can still delegate (via super.x()) to the thing you override.  We considered doing the same here (delegating to default.x()), but concluded that this failed the power-to-weight-ratio test, because usually you do not want to _refine_ an equals/toString/hashCode calculation, but instead broaden it (such as comparing arrays by contents rather than by ==.)  <br><br>If you pull on this "string" a bit, the API that you would want here is complex and enormous, and has as many tuning knobs as a Lombok.  So refactoring records that customize Object methods becomes a higher-responsibility activity.  Leave "future you" some comments for what you were thinking today.</span></span></blockquote><div><br></div><div><br></div><div>If you really really want to do it, you can use the bootstrap method in java.lang.runtime.ObjectsMethods but it's ugly.<br></div><div><br></div><div><div style="background-color:rgb(255,255,255);color:rgb(8,8,8)"><div style="background-color:rgb(255,255,255);color:rgb(8,8,8)"><div style="background-color:rgb(255,255,255);color:rgb(8,8,8)"><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><span style="color:rgb(0,51,179)">public class </span><span style="color:rgb(0,0,0)">CallingRecordToStringDemo </span>{<br><br>  <span style="color:rgb(0,51,179)">record </span><span style="color:rgb(0,0,0)">Foo</span>(<span style="color:rgb(0,0,0)">String </span>blah, <span style="color:rgb(0,51,179)">int </span>value) {<br>    <span style="color:rgb(0,51,179)">private static final </span><span style="color:rgb(0,0,0)">MethodHandle </span><span style="color:rgb(135,16,148);font-style:italic">TO_STRING</span>;<br>    <span style="color:rgb(0,51,179)">static </span>{<br>      <span style="color:rgb(0,51,179)">var </span><span style="color:rgb(0,0,0)">lookup </span>= <span style="color:rgb(0,0,0)">MethodHandles</span>.<span style="font-style:italic">lookup</span>();<br>      <span style="color:rgb(0,51,179)">var </span><span style="color:rgb(0,0,0)">components </span>= <span style="color:rgb(0,0,0)">Foo</span>.<span style="color:rgb(0,51,179)">class</span>.getRecordComponents();<br>      <span style="color:rgb(0,0,0)">CallSite callsite</span>;<br>      <span style="color:rgb(0,51,179)">try </span>{<br>        <span style="color:rgb(0,0,0)">callsite </span>= (<span style="color:rgb(0,0,0)">CallSite</span>) <span style="color:rgb(0,0,0)">ObjectMethods</span>.<span style="font-style:italic">bootstrap</span>(<span style="color:rgb(0,0,0)">lookup</span>,<br>            <span style="color:rgb(6,125,23)">"toString"</span>,<br>            <span style="color:rgb(0,0,0)">MethodType</span>.<span style="font-style:italic">methodType</span>(<span style="color:rgb(0,0,0)">String</span>.<span style="color:rgb(0,51,179)">class</span>, <span style="color:rgb(0,0,0)">Foo</span>.<span style="color:rgb(0,51,179)">class</span>),<br>            <span style="color:rgb(0,0,0)">Foo</span>.<span style="color:rgb(0,51,179)">class</span>,<br>            <span style="color:rgb(0,0,0)">Arrays</span>.<span style="font-style:italic">stream</span>(<span style="color:rgb(0,0,0)">components</span>).map(<span style="color:rgb(0,0,0)">RecordComponent</span>::getName).collect(<span style="color:rgb(0,0,0)">Collectors</span>.<span style="font-style:italic">joining</span>(<span style="color:rgb(6,125,23)">";"</span>)),<br>            <span style="color:rgb(0,0,0)">Arrays</span>.<span style="font-style:italic">stream</span>(<span style="color:rgb(0,0,0)">components</span>).map(c -> {<br>              <span style="color:rgb(0,51,179)">try </span>{<br>                <span style="color:rgb(0,51,179)">return </span><span style="color:rgb(133,22,145)">lookup</span>.unreflect(c.getAccessor());<br>              } <span style="color:rgb(0,51,179)">catch </span>(<span style="color:rgb(0,0,0)">IllegalAccessException </span>e) {<br>                <span style="color:rgb(0,51,179)">throw new </span>AssertionError(e);<br>              }<br>            }).toArray(<span style="color:rgb(0,0,0)">MethodHandle</span>[]::<span style="color:rgb(0,51,179)">new</span>));<br>      } <span style="color:rgb(0,51,179)">catch </span>(<span style="color:rgb(0,0,0)">Throwable </span>e) {<br>        <span style="color:rgb(0,51,179)">throw new </span>AssertionError(e);<br>      }<br>      <span style="color:rgb(135,16,148);font-style:italic">TO_STRING </span>= <span style="color:rgb(0,0,0)">callsite</span>.dynamicInvoker();<br>    }<br><br>    <span style="color:rgb(158,136,13)">@Override<br></span><span style="color:rgb(158,136,13)">    </span><span style="color:rgb(0,51,179)">public </span><span style="color:rgb(0,0,0)">String </span><span style="color:rgb(0,98,122)">toString</span>() {<br>      <span style="color:rgb(0,51,179)">try </span>{<br>        <span style="color:rgb(0,51,179)">return </span>(<span style="color:rgb(0,0,0)">String</span>) <span style="color:rgb(135,16,148);font-style:italic">TO_STRING</span>.invokeExact(<span style="color:rgb(0,51,179)">this</span>);<br>      } <span style="color:rgb(0,51,179)">catch </span>(<span style="color:rgb(0,0,0)">Error </span>e) {<br>        <span style="color:rgb(0,51,179)">throw </span>e;<br>      } <span style="color:rgb(0,51,179)">catch </span>(<span style="color:rgb(0,0,0)">Throwable </span>e) {<br>        <span style="color:rgb(0,51,179)">throw new </span>AssertionError(e);<br>      }<br>    }<br>  }<br><br>  <span style="color:rgb(0,51,179)">public static void </span><span style="color:rgb(0,98,122)">main</span>(<span style="color:rgb(0,0,0)">String</span>[] args) {<br>    <span style="color:rgb(0,0,0)">System</span>.<span style="color:rgb(135,16,148);font-style:italic">out</span>.println(<span style="color:rgb(0,51,179)">new </span>Foo(<span style="color:rgb(6,125,23)">"blah"</span>, <span style="color:rgb(23,80,235)">42</span>));<br>  }<br>}</pre></div></div></div></div><div><br></div><div>We also do not want to close the door to supporting super.x() if at some point in the future if the VM spec is changed to introduce a way to generate bridge methods at runtime.</div><div>The record methods toString/equals/hashCode will be declare as abstract bridge method in that case.<br></div><div><br></div><div>regards,</div><div>Rémi</div><div><br></div><blockquote style="border-left:2px solid rgb(16,16,255);margin-left:5px;padding-left:5px;color:rgb(0,0,0);font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt"><span style="font-size:large"><span style="font-family:monospace"><br><br></span></span><br><div>On 9/21/2023 1:00 PM, David Alayachew wrote:<br></div><blockquote><div dir="ltr"><div class="gmail_default" style="font-family:monospace">Hello Amber Dev Team,</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Let's say I have a record like the following.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">record ComplexRecord(int blah /* and many more components */) {}</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Next, let's say that I want to override my toString, to include some derived information.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Obviously, putting the derived info into the toString is easy, but how do I go about INCLUDING it with my original implementation of toString that was magically created for me by Java?</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">If I try to fully recreate my toString, I run the risk of it becoming out-of-date upon refactor. Best I can come up with is nesting another record with the toString overloaded. Also not ideal.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Thank you for your time!</div><div class="gmail_default" style="font-family:monospace">David Alayachew<br></div></div></blockquote><br><br></blockquote></div></div></div></blockquote></div>