Looking ahead: pattern assignment

Remi Forax forax at univ-mlv.fr
Fri Mar 12 22:14:42 UTC 2021

> De: "Alan Malloy" <amalloy at google.com>
> À: "Brian Goetz" <brian.goetz at oracle.com>
> Cc: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Envoyé: Vendredi 12 Mars 2021 22:58:44
> Objet: Re: Looking ahead: pattern assignment

> try-with-resources is a little more subtle than the other contexts. Suppose that
> I write:
> try (Foo(Bar x) = ...) {
> ...
> }

> What should be closed in the finally? The variable x that we bound to, or the
> Foo that contained it?

The instance of Foo, not the instance of Bar. 

> Both answers seem a little weird to me. Might it be better not to allow patterns
> in this context ?

It can be handy if we have a pattern method that decomposes the Closeable, by example we have a pattern method HttpRequest.parse() that returns the header and the content of the HTTP request 

try (HttpRequest.parse(var header, var content) = getAHttpRequestFrom(...)) { 


> On Fri, Mar 12, 2021 at 12:41 PM Brian Goetz < [ mailto:brian.goetz at oracle.com |
> brian.goetz at oracle.com ] > wrote:

>> While this is not on the immediate horizon, I think we are ready to put the
>> pieces together for pattern assignment. I think we now understand the form this
>> has to take, and the constraints around it.

>> Just as we were successfully able to unify pattern variables with locals*, I
>> would like to be able to unify pattern assignment with assignment.

>> A pattern assignment takes the form:

>> P = e

>> where P is a pattern with at least one binding variable that is total (perhaps
>> with remainder) on the type of e. (If P has some remainder on the type of e,
>> then the assignment will throw NPE or ICCE.) All bindings in P are in scope and
>> DA for the remainder of the block in which P appears, just as with local
>> variable declaration.

>> 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) -> { ... }

>> (And I'm sure I forgot some.)

>> Minimally, we have to align the semantics of local variable declaration with
>> assignment with that of pattern matching; `T t = e` should have the same
>> semantics whether we view it as a local declaration plus assignment, or a
>> pattern match. This means that we have to, minimally, align the
>> assignment-context conversions in JLS 5. (If we wish to support patterns in
>> method/lambda formals, we also have to align the method-invocation context
>> conversions.)

>> Early in the game, we explored supporting partial patterns in pattern
>> assignment, such as:

>> let P = e
>> else { ... }

>> where the `else` clause must either complete abruptly, or assign to all bindings
>> declared in `P`. (It wasn't until we unified pattern variables with locals that
>> there was an obvious way to specify the latter.) While this construct is sound,
>> it is in tension with other uses of pattern assignment:

>> - (syntactic) Its pretty hard to imagine an `else` clause without introducing
>> the assignment with some sort of keyword, such as `let`, but this limits its
>> usefulness in other contexts such as method parameter declarations;
>> - (pragmatic) It just doesn't add very much value; if the else throws, it is no
>> less verbose than an if-else.

>> The remaining case where this construct helps is when we want to assign default
>> values:

>> let Point(var x, var y) = aPoint
>> else { x = y = 0; }
>> // can use x, y here either way

>> But, I think we can get there another way, by letting patterns bind to existing
>> variables somehow (we want something like this for the analogue of
>> super-delegation and similar in pattern declarations anyway.) I won't paint
>> that bikeshed here, except to suggest that the let-else construct seems to be a
>> losing price-performance proposition.

>> I suspect the right time to formalize pattern assignment is when we formalize
>> deconstructor declarations (probably next round). In the meantime, we should:

>> - gather a complete list of contexts where pattern assignment makes sense;
>> - nail down semantics of primitive type patterns (see earlier mail);
>> - think about how to align the conversion rules in JLS 5 to align with existing
>> usage.

>> *the only remaining difference between pattern variables and locals is that
>> pattern variables have a more interestingly-shaped scope (and perhaps in the
>> future, pattern variables may have multiple declaration points in the presence
>> of OR patterns / merging via ORing of boolean expressions)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210312/36d2e797/attachment.htm>

More information about the amber-spec-experts mailing list