> 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.