> From: "Maurizio Cimadamore" <maurizio.cimadam...@oracle.com>
> To: "Brian Goetz" <brian.go...@oracle.com>, "Tagir Valeev" <amae...@gmail.com>
> Cc: "amber-spec-experts" <amber-spec-experts@openjdk.java.net>
> Sent: Tuesday, May 31, 2022 7:41:21 PM
> Subject: Re: Named record pattern

> While merging is an issue (if supported), I think early in the design we 
> settled
> on the principle that a binding variable should always only have one
> corresponding declaration (in the places where it is defined).

> So, from a language perspective, I don’t see an immediate problem, in the 
> sense
> that the annotations and finality for “s” would come from the place where “s”
> has been declared.

> From a compiler perspective, the big question is whether, even in the absence 
> of
> merging in the flow scoping rules, we could still perform merging under the
> hood, in order to speed up computation. Consider:
> sealed interface Node
> record Pair (Node fst, Node snd) { } record A (String s) implements Node {}
> record B ( int i) implements Node {}

> And then:
> case Pair (A(String s1) , A (String s2) ) -> ... case Pair (A(String s3) , B (
> int i1) ) -> ... case Pair (B( int i2) , A (String s4) ) -> ... case Pair (B(
> int i3) , B ( int i4) ) -> ...

> (for simplicity, all binding names are different, so that we do not depend on
> whether the block after -> … completes normally or not)

> Of course the first two patterns share the common subpattern A(String s1) (if
> you ignore naming differences). So it might be possible, in principle, for the
> compiler/runtime to generate an optimized decision tree in which the String
> value for the first A(…) sub-pattern is computed only once, and then shared in
> the two cases. (A similar reasoning applies to the last two patterns).

> But if the types in the first and second pattern could be annotated 
> differently,
> then we are faced with a number of challenges, as the compiler would not be
> able to just “blindly” reuse the cached values (as those values would be
> shared, and, therefore, unannotated). Instead, the compiler would have to
> assign the cached value into a fresh , correctly annotated local variable that
> is used only inside the given case . This is not impossible of course, but 
> adds
> complexity to the translation strategy, and/or might affect the number of 
> moves
> we might be able to do.

The same issue arise if the patterns parts are generated at runtime using an 
invokedynamic. 

I don't think it's an issue if we consider that inside the pattern tree, we 
have bindings and that once "->" is crossed, those bindings are materialized as 
local variables with annotations. 

I kind of easier to see it if there an invokedynamic and a carrier object. A 
switch(value) is translated to 
Object carrier = invokedynamic pattern_match(value) [send the patterns as a 
constantpool constant]; 
int index = invokdynamic extract (carrier)[binding 0 /* index */]; 
switch(index) { 
case 0 -> { 
// here we rematerialize the local variables 
String s1 = invokdynamic extract (carrier)[binding 1]; 
String s2 = invokdynamic extract (carrier)[binding 2]; 
... 
} 
case 1 -> { 
// we materialize s3 and i 
String s3 = invokdynamic extract (carrier)[binding 1]; 
int i1 = invokdynamic extract (carrier)[binding 2]; 
... 
} 
... 
} 

In a sense, this is similar to a lambda, it's not the parameter of the method 
of the lambda proxy which is annotated but the parameter of the static method 
desugared from the lambda body. 
Here, it's not the patterns part (that one that matches) which store the 
annotations but the part that extract the value from the carrier into local 
variables that stores the annotation. 

I think this idea also work if we do not use invokedynamic, the matching par 
can use a Tree or a DAG that fuses several bindings to one, it's not an issue 
if we generate local variables initialized from the binding values afterward. 

regards 

> Maurizio

Rémi 

> On 31/05/2022 17:12, Brian Goetz wrote:

>> As a confounding example that suggests that pattern variables are not "just
>> locals", in the past we talked about various forms of "merging":

>> if (t instanceof Box(String s) || t instanceof Bag(String s)) { ... }

>> or

>> case Box(String s):
>> case Bag(String s):
>> common-code;

>> If pattern variables could be annotated, then the language would be in the
>> position of deciding what happens with

>> case Box(@Foo(1) String s):
>> case Bag(@Foo(2) String s):

>> (This is the "annotation merging" problem, which is why annotations are not
>> inherited in the first place.)
> ​

Reply via email to