> On Jan 11, 2021, at 11:26 AM, Brian Goetz <brian.go...@oracle.com> wrote:
> 
> 
>> 
>> Or we could just decide that “pattern and” will likely be used a lot in case 
>> labels, but hardly at all in `instanceof` expressions, and therefore just 
>> live with having to use parentheses in the latter case.  But even with this 
>> design choice, it’s handy to have patterns distinguishable from expressions, 
>> because it helps to catch bugs when you accidentally omit the parentheses.
> 
> The parentheses don't bother me so much.  I am more concerned about making it 
> clear what is going on.  I see the following common case for AND-ed patterns 
> in instanceof: when you are matching against a structured aggregate, like a 
> Map or an XML blob:
> 
>     if (m instanceof (withMapping(k1, var v1) ANDP withMapping(k2, var v2))) 
> { ... }
> 
> I can easily imagine cases where there are a ton of ANDed patterns for taking 
> apart a document.  And there are likely to be guard/expressions mixed in too, 
> since you might want to express constraints on previously extracted bits 
> before extracting more bits.
> 
> I think the real question I'm struggling with here is: suppose we have AND 
> patterns, which we will likely want sooner or later anyway (e.g. document 
> deconstruction.)  So given that, does it make sense to have guards be a thing 
> at all, or just find a way to turn boolean expressions into a sort of 
> pattern?  And, if the latter, will users find it easier to just see boolean 
> expressions as degenerate patterns, or to "wrap" a boolean expression in a 
> pattern, as in `true(e)` or `when(e)`?
> 
> Finding a grammar for patterns that is disjoint to expressions (already hard) 
> is only a necessary, but not sufficient, condition for making it sensible to 
> treat boolean expressions as patterns.  I am worried about things like this:
> 
>     if (x instanceof P(var a, var b) & aSet.contains(a) & bSet.contains(b) & 
> Q(var c, var d)) { ... }
> 
> Here, I match to P, do a bunch of potentially complex tests on the results, 
> and then, if these tests succeed, keep matching the original target (x) to Q. 
>  I worry that the user will have lost the thread of what is going on by then. 
>  Whereas, if we rewrote as:
> 
>     if (x instanceof P(var a, var b) & true(aSet.contains(a)) & 
> true(bSet.contains(b)) & Q(var c, var d)) { ... }
> 
> the true() is more of a signal for "I'm still in pattern-conjunction world", 
> and I think it is less confusing what is going on by the time you get to the 
> end.  Though this might just be the classic "new stuff wants to look new" 
> bias.
> 
> One of the weaknesses of guards in switch is that once you have a guard, 
> you've exited "pattern world", which is strictly less expressive than 
> composing patterns with expressions into patterns. I am worried that even if 
> the semantics work like the latter, it will still feel like the former to 
> users.
> 
> As a thought-experiment, suppose that it was just impractical to have a 
> separate grammar for expressions and patterns.  What would we do then?  Would 
> we then jump on something like `true(e)` or `when(e)` or `boolean(e)` as a 
> pattern that takes a boolean expression argument and ignores its target?

Quite possibly.  But another way would be to use a form of ANDP that explicitly 
signals that an expression is to follow (because it would seem that, after 
either `instanceof` or `case`, one is known to be starting in pattern world).

        pattern PANDP pattern
        pattern PANDE expression

and each of these produces a pattern.

One possible spelling is:

        &&&   for   PANDP
        &:   for   PANDE

Thus:

    if (x instanceof P(var a, var b) &: aSet.contains(a) &: bSet.contains(b) 
&&& Q(var c, var d)) { ... }

Note that in this design we can’t use plain `&` for PANDP because after an 
expression, “& …” looks like more of the expression.  But in the previous 
example, we could choose to use `&` to connect the two expressions:

    if (x instanceof P(var a, var b) &: aSet.contains(a) & bSet.contains(b) &&& 
Q(var c, var d)) { ... }

leading to a style where you use `&:` to mean “in a pattern, and here comes a 
boolean expression as part of that pattern” and use `&` to stay in expression 
world and use `&&&` to stay in, or transition back to, the pattern world.

Reply via email to