Question about records and overriding their "magic methods"

David Alayachew davidalayachew at gmail.com
Thu Sep 21 18:40:05 UTC 2023


Hello Rémi,

Thank you for your response!

> If you really really want to do it, you can use the
> bootstrap method in java.lang.runtime.ObjectsMethods but
> it's ugly.

That's actually way better than I thought it would be. It's surprisingly
direct too.

> 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.
>
> The record methods toString/equals/hashCode will be
> declare as abstract bridge method in that case.

I brushed up on bridge methods for this response -
https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html

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.

Thank you for your time and help!
David Alayachew

On Thu, Sep 21, 2023 at 1:49 PM Remi Forax <forax at univ-mlv.fr> wrote:

>
>
> ------------------------------
>
> *From: *"Brian Goetz" <brian.goetz at oracle.com>
> *To: *"David Alayachew" <davidalayachew at gmail.com>, "amber-dev" <
> amber-dev at openjdk.org>
> *Sent: *Thursday, September 21, 2023 7:18:13 PM
> *Subject: *Re: Question about records and overriding their "magic methods"
>
> We explored this topic somewhat when designing the feature.
>
> 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 ==.)
>
> 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.
>
>
>
> If you really really want to do it, you can use the bootstrap method in
> java.lang.runtime.ObjectsMethods but it's ugly.
>
> public class CallingRecordToStringDemo {
>
>   record Foo(String blah, int value) {
>     private static final MethodHandle TO_STRING;
>     static {
>       var lookup = MethodHandles.lookup();
>       var components = Foo.class.getRecordComponents();
>       CallSite callsite;
>       try {
>         callsite = (CallSite) ObjectMethods.bootstrap(lookup,
>             "toString",
>             MethodType.methodType(String.class, Foo.class),
>             Foo.class,
>             Arrays.stream(components).map(RecordComponent::getName).collect(Collectors.joining(";")),
>             Arrays.stream(components).map(c -> {
>               try {
>                 return lookup.unreflect(c.getAccessor());
>               } catch (IllegalAccessException e) {
>                 throw new AssertionError(e);
>               }
>             }).toArray(MethodHandle[]::new));
>       } catch (Throwable e) {
>         throw new AssertionError(e);
>       }
>       TO_STRING = callsite.dynamicInvoker();
>     }
>
>     @Override
>     public String toString() {
>       try {
>         return (String) TO_STRING.invokeExact(this);
>       } catch (Error e) {
>         throw e;
>       } catch (Throwable e) {
>         throw new AssertionError(e);
>       }
>     }
>   }
>
>   public static void main(String[] args) {
>     System.out.println(new Foo("blah", 42));
>   }
> }
>
>
> 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.
> The record methods toString/equals/hashCode will be declare as abstract
> bridge method in that case.
>
> regards,
> Rémi
>
>
>
>
> On 9/21/2023 1:00 PM, David Alayachew wrote:
>
> Hello Amber Dev Team,
>
> Let's say I have a record like the following.
>
> record ComplexRecord(int blah /* and many more components */) {}
>
> Next, let's say that I want to override my toString, to include some
> derived information.
>
> 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?
>
> 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.
>
> Thank you for your time!
> David Alayachew
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20230921/6076feb3/attachment-0001.htm>


More information about the amber-dev mailing list