<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">On Oct 20, 2018, at 8:04 PM, Guy Steele <<a href="mailto:guy.steele@oracle.com" class="">guy.steele@oracle.com</a>> wrote:<br class=""><div><blockquote type="cite" class=""><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none;" class="">On Oct 20, 2018, at 12:42 PM, Brian Goetz <<a href="mailto:brian.goetz@oracle.com" class="">brian.goetz@oracle.com</a>> wrote:<br class=""><br class=""><blockquote type="cite" class=""><blockquote type="cite" class="">  case Point(var x, var y) p: ...<br class=""><br class=""></blockquote><br class="">Is there a situation where you could have reached that case without<br class="">having a reference to p? If I've understood so far:<br class=""><br class="">SomeSuperTypeOfPoint q;<br class=""><br class="">switch (q) {<br class=""> case Point(var x, var y) p: ... // p == q and p : Point<br class="">}<br class=""></blockquote><br class="">Yes, you could have gotten there via<br class=""><br class="">  switch (getAnObjectForMe()) {<span class="Apple-converted-space"> </span><br class="">      case Point(var x, var y) p:<span class="Apple-converted-space"> </span><br class="">  }<br class=""><br class="">But, one could always refactor to<span class="Apple-converted-space"> </span><br class=""><br class="">  Object o = getAnObjectForMe();<br class="">  switch (o) {<span class="Apple-converted-space"> </span><br class="">      case Point(var x, var y) p:<span class="Apple-converted-space"> </span><br class="">  }<br class=""><br class="">and we’re back to the previous case.  <br class=""></blockquote><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">I believe that @-patterns (I’ll call them that for now) are especially useful in nested situations, where it is not convenient to do that kind of refactoring:</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">  Object o = getAnObjectForMe();</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">  switch (o) {<span class="Apple-converted-space"> </span></span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">      case Line(Point(var x1, var y1) p1, Point(var x2, var y2) p2):</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span class="Apple-tab-span" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;"> </span><span class="Apple-tab-span" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: pre; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">     </span><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">// Now you have your hands on the two points as well as their x and y coordinates</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">  }</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">So the question is how much that comes up in practice.</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">But even without nesting, the original example has the benefit of having verified the type of o and made it available in p with the matched type Point.</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;" class="">This is a very convenient idiom if you want to test x and y in order to decide which method of p to call, for example.</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""></div></blockquote></div><br class=""><div class="">When working with ASTs (or sea-of-nodes neighborhoods) in a compiler,</div><div class="">you often want to match something and then do some extra ad hoc logic</div><div class="">to decide what to do with the matched parts.  But in real world cases there's</div><div class="">often some condition where you can't complete the intended transform,</div><div class="">due to some corner-case constraint failure (e.g., div-by-zero, non-loaded</div><div class="">class) and you need to return the original AST unchanged.  If I don't have</div><div class="">@-patterns I need to refactor my switch to capture the original node</div><div class="">in a temp above the switch, so that's not a direct use case for @-patterns.</div><div class=""><br class=""></div><div class="">But the patterns can get complex, with multiple nesting levels; this happens</div><div class="">routinely in compilers.  Then, I might want to return a result composed from</div><div class="">an interior node of the pattern, wired together with some extra stuff (unrelated</div><div class="">leaf nodes, for example).  If I want to use the workaround of a temp above the</div><div class="">switch, I must first refactor the single switch over a nested pattern into a</div><div class="">nested switch over simpler patterns.  That feels like falling off a cliff.</div><div class=""><br class=""></div><div class="">Here's a second, more general observation about @-patterns.  (Can you tell</div><div class="">that I like them?)  If all deconstruction patterns are always only for record types,</div><div class="">and record types are defined as being *solely* *completely* determined from</div><div class="">their deconstruction parameters (their "state vector"), then the only argument</div><div class="">for @-patterns is a weak one:  You can always recover an arbitrary interior</div><div class="">node of a pattern-matched object by rebuilding from the leaves.  The downsides</div><div class="">to this are acceptable in many cases:  Extra GC work, and extra verbosity</div><div class="">(key objection:  it's error-prone).  But that argument runs out of steam when</div><div class="">you go beyond record deconstruction.</div><div class=""><br class=""></div><div class="">If you fully combine object-oriented APIs with patterned deconstructors, you</div><div class="">must allow that an object "p" may match a pattern "foo(var x, var y)" without</div><div class="">any contract that "p" can be fully reconstructed from "x" and "y".  After all,</div><div class="">"p" is an object with potential private variables and special behaviors, even</div><div class="">if it *also* reports a match for "foo(x,y)".  So @-patterns become more useful</div><div class="">when patterns are generalized to true pattern queries over encapsulated</div><div class="">objects, rather than mere record deconstructors.  When those things nest,</div><div class="">you need to hold onto the interior nodes of the pattern via @-patterns.</div><div class=""><br class=""></div><div class="">Or else, as noted above, the workaround is to unwind the nested pattern</div><div class="">into a nested switch of simpler patterns with associated var declarations</div><div class="">for the desired interior nodes.  But, again, that's a sharp edge for users</div><div class="">who need complex nested patterns *and* ad hoc logic to visit interior nodes.</div><div class=""><br class=""></div><div class="">— John</div></body></html>