<div dir="ltr">My two cents from the Kotlin camp:<div><div><br></div><div>1. We still don't have full structural matching in Kotlin, because smart casts + unconditional destructuring work well enough for most cases (unless you are a compiler person, but we realize that such people are a minority :)). Yes, there are use cases outside compilers, but my point is that smart casts hit the sweet spot.</div><div>Plus, we didn't come up with a syntax for structural matching that would be both clear (variable usage vs definition) and clean (inserting val's everywhere makes complex patterns rather scary-looking). </div><div>So, my take on this would be: better not do it for now, and wait until it gets wide adoption in C#, since we have the luxury of someone else being brave and taking the risks already.</div><div><br></div><div>2. We've been using per-component getter methods for destructuring, which is a huge performance win compared to Scala's unapply that creates a box on every (successful) match. C++17 has gone roughly the same direction, but leveraged the templates with values as arguments. In our "open world" with static extension functions having independent functions for every component raises some questions, but if Java requires members there, it should be simpler.</div><div><br></div><div>3. And to share a little bit about smart casts (I'm flattered that you are using our terminology here ;) ): as soon as you have smart casts, the urge to get intersection types into the language strengthens, because of cases like this:</div></div><div><br></div><div>if (x is A) {</div><div>  Â  if (x is B) {</div><div>  Â  Â  Â  // x is A&B here</div><div>  Â  }</div><div>}</div><div><br></div><div>We still get away without making intersection types explicit, and will probably not add them in the very nearest future, but they become a lot less exotic with smart casts.</div></div><br><div class="gmail_quote"><div dir="ltr">On Sun, Mar 19, 2017 at 1:32 AM <<a href="mailto:forax@univ-mlv.fr">forax@univ-mlv.fr</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">----- Mail original -----<br class="gmail_msg">
> De: "John Rose" <<a href="mailto:john.r.rose@oracle.com" class="gmail_msg" target="_blank">john.r.rose@oracle.com</a>><br class="gmail_msg">
> Ã€: "Rémi Forax" <<a href="mailto:forax@univ-mlv.fr" class="gmail_msg" target="_blank">forax@univ-mlv.fr</a>><br class="gmail_msg">
> Cc: "amber-spec-experts" <<a href="mailto:amber-spec-experts@openjdk.java.net" class="gmail_msg" target="_blank">amber-spec-experts@openjdk.java.net</a>><br class="gmail_msg">
> Envoyé: Samedi 18 Mars 2017 19:50:08<br class="gmail_msg">
> Objet: Re: Pattern Matching<br class="gmail_msg">
<br class="gmail_msg">
> On Mar 18, 2017, at 10:22 AM, Remi Forax <<a href="mailto:forax@univ-mlv.fr" class="gmail_msg" target="_blank">forax@univ-mlv.fr</a>> wrote:<br class="gmail_msg">
>><br class="gmail_msg">
>> Hi guys,<br class="gmail_msg">
>> i've already implemented a kind of pattern matching in a language that run on<br class="gmail_msg">
>> the JVM (still closed source :( ),<br class="gmail_msg">
>> so i've said to Brian that i will send a summary of how it is done.<br class="gmail_msg">
><br class="gmail_msg">
> Thanks, Remi. This is useful.  At many points it parallels thinking that we have been doing.<br class="gmail_msg">
><br class="gmail_msg">
> I'm glad to see you use indy.  As with the string-concat work, there is an opportunity to perform<br class="gmail_msg">
> run-time optimizations that way, which an eager bytecode spinning approach can't touch.<br class="gmail_msg">
<br class="gmail_msg">
yes !<br class="gmail_msg">
<br class="gmail_msg">
> For example, the static compiler can inspect type relations among different case branches,<br class="gmail_msg">
> and it can make requirements such as no dead cases, but it's only at runtime<br class="gmail_msg">
> that the final type relations are available.  And even if the static compiler ignores some type<br class="gmail_msg">
> relations, the BSM for the switch can use such information to flatten the decision tree<br class="gmail_msg">
> semi-statically.<br class="gmail_msg">
<br class="gmail_msg">
yes<br class="gmail_msg">
<br class="gmail_msg">
><br class="gmail_msg">
> (My thought ATM is to forbid dead code at compile time but allow it at runtime if<br class="gmail_msg">
> the type relations have changed.  I think that's in keeping with the way we manage<br class="gmail_msg">
> other binary compatibility questions.<br class="gmail_msg">
<br class="gmail_msg">
yes,<br class="gmail_msg">
we have decided to throw an error at runtime in case of dead code mostly to report a compilation bug because we do not have a real IDE/incremental compilation.<br class="gmail_msg">
<br class="gmail_msg">
>  The runtime optimization can ignore the<br class="gmail_msg">
> static presuppositions.  This means that the semantics of switch need to be<br class="gmail_msg">
> "as if" the switch is "really just" a linear decision chain.  We save performance<br class="gmail_msg">
> by using a declarative formulation to the BSM which allows the BSM code<br class="gmail_msg">
> generator to reorganize the chain as a true switch, or shallow cascade of<br class="gmail_msg">
> switches.  BTW, we forgot the switch combinator.  Maybe we can fix this in<br class="gmail_msg">
> the next release?  More indy leftovers!  It should be used to compile switching<br class="gmail_msg">
> on strings and enums, as well as any future pattern matches on constants.<br class="gmail_msg">
> It should be optionally lazy and open, which is what I think you are also<br class="gmail_msg">
> calling for at the end of your message.)<br class="gmail_msg">
<br class="gmail_msg">
yes,<br class="gmail_msg">
switching on enums should be done using the indy too, currently swapping two constants is not backward compatible because they is maybe a switch somewhere.<br class="gmail_msg">
and +1 for adding the switch combinator in 10. I would really like to be able to tell the JIT that the tests has no side effect (maybe it can be another combinator too) even if some part of the test are not inlinable.<br class="gmail_msg">
<br class="gmail_msg">
><br class="gmail_msg">
> The theory of type safety of multiple dispatch has moved forward with Fortress.<br class="gmail_msg">
> Alternatively, if you can sugar up a visitor deployment as if it were multimethods<br class="gmail_msg">
> added as extensions, you could prove type-safety and still define apparent methods,<br class="gmail_msg">
> outside the type capsule.  When we get value types visitors will become cheaper.<br class="gmail_msg">
> Maybe at that point we can think about doing multi-method sugar that compiles<br class="gmail_msg">
> to invisible visitor classes.  (I'm not suggesting we do this now!)<br class="gmail_msg">
<br class="gmail_msg">
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.<br class="gmail_msg">
<br class="gmail_msg">
><br class="gmail_msg">
> Maybe one of our lambda leftovers will help with the problem of flow-typing.<br class="gmail_msg">
>  Â switch (val) { case A val: â€¦ }  // relax shadowing rule for some bindings??<br class="gmail_msg">
> It's a fraught question, because the anti-shadowing rule prevents confusions<br class="gmail_msg">
> which a relaxation re-introduces, if users misuse the freedom of expression.<br class="gmail_msg">
> The goal would be to guide users to shadow variables only when the shadowing<br class="gmail_msg">
> binding is somehow a logical repeat of the original binding.  This cannot be<br class="gmail_msg">
> done automatically in all cases we care about.  Tricky tradeoffs.<br class="gmail_msg">
<br class="gmail_msg">
For lambdas, a lambda is an anonymous function, and even in JavaScript, opening a function open a new scope.<br class="gmail_msg">
If the switch as a syntax close to the lambda one (and less close to the C) it may not be a big deal.<br class="gmail_msg">
<br class="gmail_msg">
 switch(val) {<br class="gmail_msg">
  Â A val -> ...<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
but given that usually you have more that one case, it will rapidly become unreadable<br class="gmail_msg">
<br class="gmail_msg">
  switch(val) {<br class="gmail_msg">
  Â A val -> foo(val)<br class="gmail_msg">
  Â B val -> foo(val)<br class="gmail_msg">
  Â ...<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
><br class="gmail_msg">
> We are also struggling with unapply.  There are several hard parts, including<br class="gmail_msg">
> the encapsulation model and the API for delivering multiple components.<br class="gmail_msg">
> The low-level parts probably require more indy-level combinators with<br class="gmail_msg">
> special JVM optimizations.  I wish we had full value types today so we<br class="gmail_msg">
> could just do tuples for multiple-value packages.  But even that is a<br class="gmail_msg">
> simulation of the true shape of the problem, and simulation has overheads<br class="gmail_msg">
> even if we stay out of the heap.  A lower-level solution which requires<br class="gmail_msg">
> no companion types at all (not even tuples) would be to reify argument<br class="gmail_msg">
> lists per se, at the same level of abstraction as method handle types.<br class="gmail_msg">
<br class="gmail_msg">
Will it work if the pattern support nested types ?<br class="gmail_msg">
  case A(B(x y), _): ...<br class="gmail_msg">
<br class="gmail_msg">
You will have to have a kind of growable arguments list very similar to the one you need to implement the method handle combinators.<br class="gmail_msg">
Technically, for the mh combinators you also need to shrink the arguments list but you can cheat if you are able to extract a sub part when doing the calls to the direct method handle.<br class="gmail_msg">
Jerome has used that trick when implementing invokedynamic on android.<br class="gmail_msg">
<br class="gmail_msg">
> That's a building block I am currently experimenting with, as a value-based<br class="gmail_msg">
> class which can be upgraded to a value type.  The type information is<br class="gmail_msg">
> encoded as (wait for it) a MethodType, interpreted with the arrows reversed.<br class="gmail_msg">
<br class="gmail_msg">
The arrow reversed MethodType is a way to represent a flatten tuple of types to a named tuple (the value type) with the same component types.<br class="gmail_msg">
<br class="gmail_msg">
So in order to represent a tuple of multiple values which are the structural value of a class, you need a reified tuple of types and you use a MethodType as a hack.<br class="gmail_msg">
<br class="gmail_msg">
Another way to see unapply is to see it as a kind 'maybe tailcall' in a continuation,<br class="gmail_msg">
if the pattern doesn't match, it tailcalls and checks the next pattern otherwise, it drops the unnecessary parameters and calls the action.<br class="gmail_msg">
In case of embedded component, the action itself is to do a 'maybe tailcall' after the component values are on stack but if the pattern doesn't match it now has to pop two stack frames.<br class="gmail_msg">
<br class="gmail_msg">
class A {<br class="gmail_msg">
  int value;<br class="gmail_msg">
  B b;<br class="gmail_msg">
<br class="gmail_msg">
  void unapply(MethodHandle[int, B] match, MethodHandle reject) {  // act as a continuation<br class="gmail_msg">
  Â  Â if (value == 0) {<br class="gmail_msg">
  Â  Â  Â reject.invokeExact(); // tail call to the next pattern<br class="gmail_msg">
  Â  Â }<br class="gmail_msg">
  Â  Â match.invokeExact(value, b);  Â  // insert the argument into the previous call, calls unapply on b if nested, calls the action otherwise<br class="gmail_msg">
  }<br class="gmail_msg">
}<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
><br class="gmail_msg">
> Thanks for the brain dump!<br class="gmail_msg">
><br class="gmail_msg">
> â€” John<br class="gmail_msg">
<br class="gmail_msg">
Rémi<br class="gmail_msg">
</blockquote></div><div dir="ltr">-- <br></div><div data-smartmail="gmail_signature"><div dir="ltr"><div>Andrey Breslav</div><div>Project Lead of Kotlin</div><div>JetBrains</div><div><a href="http://kotlinlang.org/">http://kotlinlang.org/</a><br></div><div><div>The Drive to Develop</div></div></div></div>