Looking ahead: pattern assignment
Brian Goetz
brian.goetz at oracle.com
Fri Mar 19 19:35:15 UTC 2021
>>
>> Pattern assignment should work in all of the following contexts:
>>
>> - Assignment statements: P = e
>> - foreach-loops: for (P : e) { ... }
>> - (optional) try-with-resources: try (P = e) { ... }
>> - (optional) method formals: void m(Point(var x, var y) p) { ... }
>> - (optional) lambda formals: (Point(var x, var y) p) -> { ... }
>
> It is easy (and normal) here, I think, to be a little confused. At the
> beginning I was thinking "boy inference of lambdas with target typing
> AND patterns is gonna make javac cry" - but I think the key to a lot
> of these is that whenever you see a pattern declaration, it's like if
> you had an _explicit_ type. So, while there might be magic at runtime
> to decompose the value into the binding variables, from a static
> perspective, typing the lambda:
>
> Point(var x, var y) -> distance(x, y)
>
> is no different than typing this:
>
> Point p -> distance(p.x, p.y)
>
Exactly; think of it as a syntactic desugaring
Point(var x, var y) p -> e
to
Point p -> { Point(var x, var y) = p; return e; }
My intent was actually to require the top-level variable (p) in
lambda/method formals, which emphasizes this.
> Crucially, the pattern provides an explicit type (including generic
> type arguments, at least initially).
>
> From here I guess the next step would be, for a lambda like this:
>
> Box<String>(String s) -> ...
>
> to avoid the outer `<String>` - but I'm not sure about that step. I
> think if we treat a pattern as a replacement for an explicit type,
> things works nicely and there's a simple user model to explain. If we
> make it too magic, it could be more concise, but also more confusing.
>
Agree.
> I was thinking that maybe another way to get at that is by using
> unchecked exceptions - e.g. if pattern failure raised a well-known
> unchecked exception, then users could have a chance (if they want) at
> looking as to why things failed.
>
> try {
> P p = e;
> ...
> } catch (...)
>
> The problem with this though is that the handler code is very distant
> from where the failure has happened (unlike in let/else).
>
Not only that, but if the exception is unchecked, it is really not
obvious that the match is even partial. I like that we require an
intrinsically conditional control flow construct (instanceof, switch,
catch) for partial patterns, and only allow total patterns in things
that "look total".
> And we can't really do:
>
> P p;
> try {
> p = e;
> } catch (...)
>
> Because the proposed pattern assignment doesn't support some form of
> blank declaration - e.g. a way to say:
>
> Point(int x, int y);
> if (...) {
> // assign pattern from here
> } else {
> // assign pattern from here
> }
>
> Is this something we view as a limitation?
>
It's a glass which is either P% full or (100-P)% empty :) But I would
much rather drive towards making what you wrote legal, in some way,
rather than make assignment partial in a less-than-fully-transparent way.
We've already encountered another place where we might want
bind-to-existing: composition of deconstructors/patterns. Suppose:
class A {
int a;
deconstructor(int a) { a = this.a; }
}
class B extends A {
int b;
deconstructor(int a, int b) {
* super(a);*
b = this.b;
}
}
If we can't invoke another pattern with bind-to-one-of-my-bindings, then
we'd have to write something like:
deconstructor(int a, int b) {
super(var aa) = this;
a = aa;
b = this.b;
}
While this is not the worst thing in the world, it will surely be a
persistent irritation. So *some* way to say "bind to this variable"
possibly under some restrictions (DU?) seems desirable. If we had that,
then your if-else would do the trick:
int x, y; // blank locals, therefore DU
if (!(target instanceof Point(__my x, __my y)) {
x = y = 0;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210319/0ff3c307/attachment.htm>
More information about the amber-spec-experts
mailing list