Pattern Matching
forax at univ-mlv.fr
forax at univ-mlv.fr
Tue Mar 28 15:42:19 UTC 2017
> De: "John Rose" <john.r.rose at oracle.com>
> À: "Rémi Forax" <forax at univ-mlv.fr>
> Cc: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Envoyé: Lundi 27 Mars 2017 23:39:23
> Objet: Re: Pattern Matching
> On Mar 18, 2017, at 3:32 PM, forax at univ-mlv.fr wrote:
>> The main issue of the visitor is that you have to add the accept methods on the
>> class of the hierarchy before being able to use the visitor, this is equivalent
>> to be able to insert a method or a constant into a class, which is also
>> equivalent to be able to inject the implementation of a not yet existing
>> interface.
> Good point. Some form of post-facto interface injection (if we could figure
> out the details, which is very hard) would presumably address this problem.
> The issue of visitors and matchers is important because if we introduce
> a new kind of class (data class, record class, whatever) with enhanced
> pattern capabilities, we have basically one chance to define a universal
> pattern match interface for that kind of class. (We could add it in after
> first release, but it's hard to add more than once.)
I think should can try to come with extractors/de-constructors for 10 but if we are not satisfied, we can support getters as a backup strategy (if class is immutable) and still introduce extractors in 11.
> Here's a second point of similar weight: The interface itself has parts
> which are signature-polymorphic. If you try to represent it as a classic
> Java interface you can see that the polymorphism causes boxing:
> interface Matchable<R extends Matchable.Result> {
> R match();
> }
> Whatever the API structure is for match patterns and results,
> the result eventually has to deliver a tuple of extracted values.
> But there is no good way (yet, until value types and any-generics)
> to express the type of a tuple. So we get List<Object>, etc.
yes, very true.
if Optional and tuples are in the language, writing an API for extractor is easy, it's the unapply of Scala.
As you already said, it still requires to compute the value of an extracted value even if the value will be ignored by a '_'.
> The closest we can get to a tuple type in the JVM is an argument
> list type, reified as a MethodType and accepted by a MethodHandle.
> Therefore, I think a workable "Matchable" API can involve method
> handles and be type-classified by MethodTypes (returning a
> conventional void result).
> As a first cut:
> interface Matchable<MT extends MethodType<void, A...>> {
> boolean match(MethodHandle<MT> collector);
> MT matchType();
> }
> (The pattern part of the match is left out for clarity.
> You can put it back in easily enough as another argument
> to the "match" call. Maybe match is overloaded by pattern
> kind.)
This is the part i do not like with the unapply, unapply is a mix of an extractor, i.e. something that decompose an object into several components and at the same time something that checks if the pattern is accepted.
My gut feeling is that we should only provide a deconstructor, the pattern recognition should be encoded in term of component values thus independent of a peculiar object once it has be decomposed.
By example with:
int j = ...
switch(i) {
case A(B(int x, _), j) : ...
}
A should be decomposed using the extractor and the second component value should be compared with the value of j, the comparison should be installed by the bootstrap method, independently of the way the extractor is written.
> The type variable decorations are ill-defined and have to
> be stripped out of the real code.
> Second cut:
> interface Matchable<MT extends MethodType<void, A…>> {
> BUF match(); // returns null on failure, buffered match-values on success
> <R> R matchExtract(BUF, MethodHandle<MethodType<R, A…>> collector);
> MT matchType();
> }
> The extract calls either look into the match-result buffer
> for the required match components, or (as an optimization)
> might look directly into the object fields, if it is safe to do so.
> A third cut might break the mold completely (of a classic
> interface) and present the Matchable API as a statically
> linkable bundle of method handles, one bundle per match
> API binding (i.e., per concrete class). The bundle would
> look like:
> interface Extractor<T, BUF, MT extends MethodType<void, A…>> {
> MethodHandle<BUF, T> matchHandle(); // null on failure, T or other value on
> success
> MethodHandle<?, T, BUF> componentHandle(int i); // extract one of the A values
> MT matchType();
> Class<T> targetType();
> Class<BUF> bufferType();
> }
> You could omit the BUF type completely, but there is a big cost:
> There is no way for the T object to deliver a tuple of types apart from
> being willing at any moment to be the subject of an accessor call.
> Those accessor calls will need in general to do redundant calculations
> and are subject to race conditions which might make the match
> disappear before the components were extracted.
> The presence of the T type (alongside BUF) in the component
> handles allows an object with immutable fields to deliver those
> particular values by direct access, instead of copying them
> through a buffer object.
> The BUF type is secret to the implementation of T. You can
> use an extractor without knowing it except via a wildcard.
I still think you do not need
so only for the extractor part, what a user can write is
data class A(B b, int y) {
public extractor B, int () {
return b, y;
}
}
and the compiler can transform it to
// attribute data class
class A {
private final B b;
private final int y;
...
// attribute: components: B, int
// attribute: extractor, synthetic?
public Empty <extractor>() {
return invokedynamic (B, int)Empty (b, y);
}
}
the return value is a value type dynamically created, an anonymous value type?, maybe masqueraded by an empty interface (Empty), allocated by invokedynamic and that can not be called by anything else than a MethodHandle (from the bootstrap method of the switch) that will de-structure the value type as the component values of the call to the implementation part of the pattern matching.
> — John
Rémi
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20170328/794d2aab/attachment.html>
More information about the amber-spec-experts
mailing list