I agree with this analysis, especially the comment about “the One True Source 
Of Expressiveness: composition”.

—Guy

> On Jan 18, 2021, at 10:20 AM, Brian Goetz <brian.go...@oracle.com> wrote:
> 
> I think the question here is mostly one of terminology.  Let’s restate the 
> problem first.  The canonical example is:
> 
>    if (p instanceof Point(var x, var y) && x == y) { /* diagonal */ }
> 
> Here, the language is fully powerful enough for the pattern to 
> test-and-extract on Point-ness, and the conjoined clause refines with an 
> arbitrary predicate.  This comes “for free” because expressions compose.  
> 
> The switch analogue is:
> 
>     switch (p) {
>        case Point(var x, var y): 
>           // I want to do one thing for diagonal points, and something else 
> for other points
>     }
> 
> This is where it gets messy, because switch gives you one chance to classify 
> the target, and you have to live with that.  I think we all agree that making 
> cases powerful enough to include type / deconstruction patterns has a “glass 
> half empty” character to it; there will be plenty of “cases” where we can’t 
> express what we want using a pattern switch, at least not without some ugly 
> and error-prone contortions.  
> 
> There have been three ways proposed out of this mess:
> 
> 1.  Have a “continue” statement that lets a case body say “whoops, I fell 
> into the wrong case, please keep trying to match at the next case.”  
> 2.  Have an explicit feature of the switch statement to refine the pattern 
> with a predicate, such as: “case P when(e)”.
> 3.  Find a way to turn boolean expressions into patterns, and just use 
> pattern-AND composition.
> 
> The confusion over terminology stems from the fact that we could describe all 
> these as sorts of guards: 1 is an “imperative guard”, 2 is a “switch guard”, 
> and 3 is a “guard pattern.”  Which underscores we want some kind of 
> guarding-feature no matter what.  
> 
> John has defended #1 as being a good “primitive”.  And from a VM-design 
> perspective, I agree; it is the sort of “control flow assembly language” we 
> might want, and it covers 100% of the cases.  Unfortunately, as a user tool, 
> it has fewer good characteristics; it is like fallthrough squared.  
> 
> #2 had seemed like a “tolerable evil.”  From a language design perspective, 
> it is surely a “bag” of sorts; it is limited in purpose, and doesn’t compose 
> with other features.  It’s basically a “patch”, but one that users might find 
> easy enough to reason about.  It is a candidate for a “worse is better” 
> solution.
> 
> #3 is a feature that should make a PL designer happy; it is strictly more 
> powerful than #2, is more broadly applicable (we can use it in other contexts 
> where patterns are allowed), and its power derives from the One True Source 
> Of Expressiveness: composition.  
> 
> Even adding constant patterns or relational patterns (>= 0) doesn’t really 
> remove the need for some sort of guarding.  
> 
> The question is how we want to get there.  #3 amounts to “turn a guard into a 
> pattern”.  We might call it a “guard pattern”, or a “boolean pattern”.  But 
> the terminology has gotten fuzzy, I agree.
> 
> For the record, I am now strongly in Camp #3: we want AND pattern combination 
> anyway, so let’s find some way to turn a boolean expression into a pattern 
> and call that a win.  
> 
>> On Jan 18, 2021, at 3:03 AM, Remi Forax <fo...@univ-mlv.fr> wrote:
>> 
>> Hi everybody,
>> following the discussion about && / and between guards and patterns,
>> i don't think i've a clear understanding on what is a pattern and what is a 
>> guard.
>> 
>> When we first discuss of guards, the separation was a kind of clean, a 
>> pattern match something and a guard provides further refinements.
>> By example, with a made a syntax,
>> case Point(var x, var y) && x > 0 && y > 0
>> Point(var x, var y) is the pattern and x > 0 and y > 0 are the guards.
>> 
>> So a pattern asks if something match and a guard uses the binding to add 
>> restrictions.
>> 
>> As Brian said, in C#, you can directly test inside a pattern, using a weird 
>> syntax chosen by C# like >0,
>> so the same example can be rewritten
>> case Point(>0, >0)
>> and with the bindings, i suppose something like
>> case Point(var x >0, var y >0)
>> 
>> Here the line between a pattern and a guard starts to become blurry, because 
>> >0 is pattern.
>> 
>> So if there a difference between a pattern and a guard ?
>> 
>> regards,
>> Rémi
>> 
>> 
>> 
>> 
> 

Reply via email to