> On Jan 11, 2021, at 11:26 AM, Brian Goetz <[email protected]> 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.