Fwd: How will record destructing be implementable without multiple return values?
Brian Goetz
brian.goetz at oracle.com
Sat Apr 27 01:15:14 UTC 2019
The following was received on the amber-spec-comments list. Responses inline.
> From: Steven Stewart-Gallus <sstewartgallus at sstewartgallus.com>
> Subject: How will record destructing be implementable without multiple return values?
> Date: April 26, 2019 at 8:26:21 PM EDT
> To: amber-spec-comments at openjdk.java.net
>
> Hello,
>
> It seems like there are potential plans for record destructuring but
> not fully hashed out yet in a formal JEP
> https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html? The
> formal JEPs https://openjdk.java.net/jeps/305 seem to be much more
> scaled back.
“Scaled back” is not the right way to describe it; “phased implementation” is a much more accurate description. One of the luxuries of the new rapid cadence is that we can deliver things in more manageable chunks.
> Record destructuring doesn't seem implementable efficiently to me on
> the JVM as shown.
Your assumption here is that one allocation per successful match is “prohibitively expensive.” While this assumption is patently false (Scala’s pattern matching potentially does many allocations per match, and users love it), we can in fact do deconstruction patterns without allocation at all.
You are correct that it would be much more convenient if we had multiple return at the VM level (or out parameters, or uplevel local access), we can implement pattern matching efficiently without these. We represent a pattern as a bundle of method handles, where the first method handle does the “do you match” part, and the remaining method handles extract individual binding variables. There’s an old writeup of the approach here (it’s been refined since then):
http://cr.openjdk.java.net/~briangoetz/amber/pattern-match-translation.html <http://cr.openjdk.java.net/~briangoetz/amber/pattern-match-translation.html>
and a talk I did at JVMLS a few years ago with more detail:
https://www.youtube.com/watch?v=n3_8YcYKScw&list=PLX8CzqL3ArzXJ2EGftrmz4SzS6NRr6p2n&index=2&t=2775s <https://www.youtube.com/watch?v=n3_8YcYKScw&list=PLX8CzqL3ArzXJ2EGftrmz4SzS6NRr6p2n&index=2&t=2775s>
Deconstruction of a record is the easy case, because the record itself can be used as a “carrier” for the extracted values. More sophisticated patterns may require a standalone carrier object to hold the bindings. The mechanism outlined here can gracefully upgrade from using standard objects to using value types in a binary compatible way (without recompiling either the record or the matching client) when value types are available.
> I guess this is why the JEP was scaled back?
> Suppose we have a Point class and we want to destruct in radians
> format.
>
> switch (obj) {
> case Point.ofRadians(var theta, var radius):
> return doStuff(theta, radius);
> }
>
> How can you return multiple values to make this work without
> allocating? Or is this just planned to be put on the back burner
> until things like Project Valhalla go through which would make this
> much less of an issue. I think an encoding like:
>
> public static Synthetic ofRadians(Object obj) {
> if (obj instanceof Point p) {
> return new Synthetic(true, p.theta(), p.radius());
> }
> return new Synthetic(false, 0, 0);
> }
> public inline record Synthetic(int matched, int theta, int radius) {
> }
>
> might work but it seems silly.
>
> Or am I missing something and this isn't really a problem.
>
> Thank you,
> Steven Stewart-Gallus
More information about the amber-dev
mailing list