New pattern matching doc
forax at univ-mlv.fr
forax at univ-mlv.fr
Mon Jan 11 21:20:39 UTC 2021
> De: "Brian Goetz" <brian.goetz at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Envoyé: Lundi 11 Janvier 2021 18:44:17
> Objet: Re: New pattern matching doc
>>> 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.
> You can, as the document says. That's an instance pattern (abstract or not). But
> that doesn't mean that static patterns don't also make sense. There's a reason
> we have static methods, and all the same reasons apply to static patterns.
>>> 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.
> I think you are confused about how this works. Consider this class (deliberately
> terrible syntax):
> class FriendOfOptional {
> static<T> Optional<T> makeOptional(T t) { return Optional.of(t); }
> static<T> __partial
> __pattern
> __ name = "presentOptional"
> __target(Optional<T> opt)
> __bindings(T t)
> __body {
> if (opt.isPresent()) __MATCH_SUCCEED(opt.get());
> else __MATCH_FAIL;
> }
> }
> }
> Here, we've written our own Optional factory, say, just because we don't like
> the name Optional::of. That's allowed! And we've written our own pattern to
> deconstruct a present optional. Everything here is static.
> Now, we have a switch:
> switch (o) {
> case FriendOfOptional.presentOptional(var contents): ...
> }
> How do we do this dispatch?
> - Let X be the static type of the operand
> - Perform "pattern overload selection" looking for
> FriendOfOptional::presentOptional
> - Type check arity and types of selected pattern
> - Note (from selected overload) that the target type of FOO::presentOptional is
> Optional<T>, call that Y
> - Type check that X (type of switch target) is cast convertible to Y (pattern
> target) without an unchecked conversion
> - If X is not a subtype of Y, insert an additional instanceof Y check in the
> case before trying to match to the FOO::presentOptional pattern (**)
> - "Invoke" the pattern FOO::presentOptional with argument ((Y) o) if the pattern
> is static, or on receiver ((Y) o) if instance
> All of this happens whether the pattern is an instance or static pattern; what
> differs is only (a) how we do overload selection (which has not been fully
> specified yet) and (b) how we pass the target to the pattern (receiver vs
> argument.)
> Is it the ** part that is confusing you?
>> 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.
> Then I'm going to ask that you be clearer on what you mean then! Because you
> started with a pile of "this is wrong, this doesn't work", which never helps,
> especially when it's not clear you've really understood what I'm shooting at
> first. Maybe start with some clarifying questions about the parts you're fuzzy
> on?
To summarize, this is what i'm proposing,
using the same notation as Alan, we have two syntax
IDENTIFIER(BINDINGS), the unqualified pattern, and Qualifier.IDENTIFIER(BINDINGS), the qualified pattern.
For the qualified pattern, Qualifier.IDENTIFIER(BINDINGS) references
- either an instance method inside the class Qualifier, with 'this' being the value switched upon
- or a static method inside the class Qualifier, the first parameter containing the value switched upon
For the unqualified pattern, IDENTIFIER(BINDINGS), it is equivalent to
- AnotherType(BINDINGS) if the identifier is the type AnotherType (it's the deconstruction pattern)
- either Type.IDENTIFIER(BINDINGS) and the rules above applied (it's the inference rule of Tagir)
- or AnotherType.IDENTIFIER(BINDINGS) if there is an import static AnotherType.IDENTIFIER
The rules of the qualified pattern are here because you may own or not the type you want to to do pattern matching on it, so you can either specify the pattern inside the class or outside the class
(and as i said, an instance method can be overriden + can access to super members).
The rules of the unqualified pattern are the usual Java rules, find the qualifier and then apply the qualified pattern.
regards,
Rémi
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210111/8f0bf35d/attachment-0001.htm>
More information about the amber-spec-experts
mailing list