Destructuring / Patterns in for-each

Brian Goetz brian.goetz at oracle.com
Wed Jan 20 00:16:38 UTC 2021


Yes, absolutely this is on the radar.  There is a whole constellation of 
related features to use total patterns in various places.  The use in 
for-loops is a generalization of the pattern-bind statement; right now, 
you can declare locals as

     Foo f = expr

If you squint, you can see this as an unconditional pattern bind; the 
LHS is a pattern (`Foo f` is a type pattern) that declares a binding 
variable `f`, the RHS can be a match target, and the pattern is total on 
the static type of the target, so no conditional wrapping (instanceof, 
switch, try, etc) is needed. If so, we can generalize this to 
deconstruction patterns:

     Point(var x, var y) = aPoint

Readers might find this weird at first, so we've considered other 
syntaxes (e.g., a `let` statement), but I prefer this version for the 
very reason you have cited -- that it can be lifted directly into things 
like foreach loops, try-with-resources blocks, method declarations, and 
any other places where "locals" are declared.

Your Map.Entry inquiry illustrates one of the reasons why we want 
patterns to be full-fledged class members; if we can put a 
deconstruction pattern on an interface like `Map.Entry` (and there's no 
reason we can't), we can iterate a map with:

     for (Map.Entry(var key, var value) : map.entrySet())
         System.out.printf("%s: %s%n", key, value);

This isn't quite as concise as Python's

     for x, y in dict.items():
         ...

but it's close.

So: yes, yes, and bonus yes.

On 1/19/2021 7:06 PM, August Nagro wrote:
> Hello,
>
> I wouldn't be surprised if this has been thought of / discussed before, but
> I would love to some day use destructuring in for-each loops, kind of like
> the for-of loop in JavaScript.
>
> For example, instead of
>
> record Point(double x, double y) {};
>
> double greatestMagnitude = 0.0;
> Point[] points = ...
>
> for (Point p : points) {
>    greatestMagnitude =
>      max(greatestMagnitude, sqrt(pow(p.x(), 2) + pow(p.y(), 2)))
> }
>
> We could have:
>
> for (Point(var x, var y) : points) {
>    greatestMagnitude =
>      max(greatestMagnitude, sqrt(pow(x, 2) + pow(y, 2)))
> }
>
> Not a huge improvement in this example, but there's a lot of code like
> this. It would be a nice bonus if Map.Entry could be destructured, but I
> don't see how that would be possible since it's an interface.
>
> Regards,
>
> August



More information about the amber-dev mailing list