> De: "Brian Goetz" <brian.go...@oracle.com> > À: "Remi Forax" <fo...@univ-mlv.fr> > Cc: "amber-spec-experts" <amber-spec-experts@openjdk.java.net> > Envoyé: Lundi 11 Janvier 2021 16:38:31 > Objet: Re: New pattern matching doc
>>>> By example, case Optional.of() is called the static pattern in the >>>> document, but >>>> the corresponding member is not static at al, it has to have access to the >>>> values of the instance. >>> This is not correct. The pattern `Optional.of()` is truly static. >> The pattern is static, but perhaps not as "static" in a static method call, >> but >> as "static" in a method reference way. >> For Optional.of(var x), the implementation needs to take a look to the >> content >> of the Optional, thus the implementation is not static as in static method. > For static patterns, the target is passed as an argument. Just like the > following method: > class Foo { > static<T> T unboxIfPresentOrNullIfAbsent(Optional<T> target) { > return target.isPresent() ? target.get() : null; > } > } > This is a static method that "matches" present optionals, and returns their > contents if present, or a sentinel if not. The static pattern Optional::of > does > the same, just not as a method. It can not, for several reasons, first you should be able to declare a "virtual" pattern method on an interface and a class that implements that interface should provide a specific implementation of that pattern. Otherwise you are re-enacting the game "extension method vs default method" but with a different outcome. Moreover, you can not access to super class members (via super) if the method is a static method. That's why a lambda like () -> super.x is desigared to an instance method and not a static method. [...] >>> For `case Foo(int x)`, this is a deconstruction pattern, and Foo is the >>> name of >>> a class, not of a pattern. Just like with constructors, we look in class Foo >>> (not superclasses) for a matching deconstructor. The target becomes the >>> receiver of the pattern invocation. >> The application test is an instanceof + a call to the deconstructor which as >> a >> special linking semantics for transferring the bindings > I am not sure I like the word "call" here, as it suggests that you are trying > to > cast these things as methods. Under the hood, of course there are going to be > methods, because that's what the JVM offers us. But we're talking about the > language model here, so I'd like to avoid confusing words. But yes, it is as > if > we are "calling" the deconstructor which puts the bindings somewhere the > "caller" can get them. >>> For `case Foo.of(var x)`, this is a static pattern. Foo is the name of a >>> class, >>> and `of` is the name of a declared static pattern in Foo. The target >>> becomes an >>> argument of the pattern invocation. >> The application test is an instanceof + a call to the method an instance >> method >> of() with, i hope, the same special semantics for transferring the bindings. > Same transfer of the bindings, but it is not an instance method; static > patterns > translate to static artifacts. The switch target (the Foo) is passed as an > ordinary parameter. Then, there is an additional wrinkle on the bindings > transfer, because the pattern might say "nope, not really a Foo of anything", > in which case we "transfer" a sentinal that says "these bindings are no good, > don't use them." >> Unlike the deconstructor, this instance method can be overridden (you want >> to be >> able to declare such method on an interface). > No, but instance patterns can. >> It's more that i want that all patterns that have bindings to share the same >> meta-protocol (the way to bind bindings). > That is how this works. Here's the full (abstract) protocol. > - Every pattern has a target, which is "passed" from the client to the > pattern. > - Every pattern can have zero or more output bindings, which are "passed" back > from the pattern to the client. > - Patterns can succeed or fail. In case of failure, they return no bindings. > - Some patterns are constrained to never fail (total patterns.) > - Patterns may take additional (input) arguments. (Canonical example: a > "regex" > pattern that takes the regex pattern as well as the target.) > Different patterns use different subsets of this protocol. Total patterns > don't > make use of the "might fail" channel; none of the patterns so far make use of > the "extra args" channel. Yes, we agree on this part > This maps to instance/static in a straightforward way: for instance patterns, > the target is the receiver, for static patterns, it is passed as the first > input argument. And here we disagree because you are mixing how the pattern is used inside the switch with how it is declared inside the class. When you use a pattern inside a switch, you have to specify the type because you may first have to do an instanceof, but it doesn't mean that the method that declare the pattern has to be static. >> But a constructor neither need a special keyword nor have a semantics >> different >> from a classical methods > But this is just not true! Constructors are different in both syntax and > semantics from classical methods. You have butchered my original email on that part, i was just saying that in term of linking all pattern methods (destructor, static pattern implemented using an instance method or a static methods), they all should be presented the same way for a user that want to declare them. > If I had to read between these pages of indirect objections, I'm tempted to > guess that this is all really just: "I'm disappointed that we didn't make > constructors just be static methods in the first place, and I want to fix that > mistake now?" Nope, I'm not disappointed at all, i think we are slowly going to the right direction. Rémi