[pattern-switch] Guards
Guy Steele
guy.steele at oracle.com
Mon Jan 11 17:38:14 UTC 2021
> On Jan 11, 2021, at 11:26 AM, Brian Goetz <brian.goetz at 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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210111/9b0894dc/attachment.htm>
More information about the amber-spec-experts
mailing list