Guards redux
Guy Steele
guy.steele at oracle.com
Wed Mar 10 19:29:48 UTC 2021
> On Mar 10, 2021, at 9:47 AM, Gavin Bierman <gavin.bierman at oracle.com> wrote:
>
> Okay, so it seems like our initial stab at guards and a pattern conjunction
> operator needs some finessing.
>
> Here's another take, inspired by Guy's emails.
>
> Step 1. Let's use `p && e` as the way to guard a pattern p with a boolean
> expression e.
>
> Step 2. [Now or later] Let's use `&` (and `|`) as the conjunction and
> disjunction operators on patterns.
>
> There are a couple of immediate parsing puzzlers:
>
> * e instanceof String s && s.length() > 2
>
> This parses as `(e instanceof String s) && s.length() > 2` today. We need to be
> careful that our grammar continues to make this the case (see below). We will
> also introduce a parenthesized pattern, which you can use if you want the
> dangling `&& s.length() > 2` to parse as a guard for the `String s` type
> pattern. (It is extremely fortuitous that the functional behavior of both
> expressions is the same, but either way I think this is a simple rule.)
>
> * case p && b -> c -> b
>
> Now we have some ambiguity from the `->` in a lambda expression and in a switch
> rule. Fortunately, again I think we can just lean into the grammar to get what
> we want. At the moment, the grammar for expressions is:
>
> Expression:
> LambdaExpression
> AssignmentExpression
>
> As a lambda expression can never be a boolean expression it can never
> meaningfully serve as a guard for a pattern. Great!
Good catch here by Gavin; I had completely overlooked this potential difficulty with `->`.
> So, I'd like to suggest this grammar for patterns (including pattern conjunction
> and pattern disjunction operators for completeness but we can drop them from the
> first release):
>
> Pattern:
> : ConditionalOrPattern
> : ConditionalOrPattern `&&` Guard
Let me suggest this alternative:
Pattern:
: ConditionalOrPattern
: ConditionalAndPattern `&&` Guard
It is certainly true that in Java, `|` has higher precedence than `&&`, but I regard this as a pitfall for the programmer, an unfortunate fact inherited from C that does not cause such trouble in Java because (a) programmers tend not to mix the use of `&` and `|` on the one hand and `&&` and `||` on the other in boolean expressions, and (b) Java fortunately does not allow integers to be used as if they were booleans, so any mixture of `&` and `|` used on integers with use of `&&` and `||` is likely to be mediated by relational operators, and perhaps also parenthesized.
But if the syntax of patterns includes `|` for pattern disjunction, the programmers will be positively encouraged to use mixtures of `|` and `&&`, and I think this is likely to lead to confusion. Consider:
case Map.with(key1)(var theValue) | Map.with(key2)(var theValue) && theValue > 0:
Question: does the guard apply if the pattern Map.with(key1)(var theValue) successfully matches?
I believe the grammar adjustment I propose above would force the programmer to clarify by using parentheses:
case (Map.with(key1)(var theValue) | Map.with(key2)(var theValue)) && theValue > 0:
or
case Map.with(key1)(var theValue) | (Map.with(key2)(var theValue) && theValue > 0):
> ConditionalOrPattern:
> : ConditionalAndPattern
> : ConditionalOrPattern `|` ConditionalAndPattern
>
> ConditionalAndPattern:
> : PrimaryPattern
> : ConditionalAndPattern `&` PrimaryPattern
>
> PrimaryPattern:
> : TypePattern
> : RecordPattern
> : ArrayPattern
> : `(` Pattern `)`
>
> Guard:
> : AssignmentExpression
Yes, “AssignmentExpression” is the right thing here.
> Along with the following change to the grammar for instanceof:
>
> InstanceofExpression:
> : RelationalExpression `instanceof` ReferenceType
> : RelationalExpression `instanceof` PrimaryPattern <-- Note!
Yes, “PrimaryPattern”.
> Some consequences:
>
> p1 & p2 & p3 && g1 && g2 parses as ((p1 & p2) & p3) && (g1 && g2), yay!
>
> p1 && g1 & p2 && g2 needs to be bracketed as (p1 && g1) & (p2 && g2) to parse
> properly. But that's okay, as I think the second is much clearer.
Or as `(p1 && g1) & p2 && g2`, but that’s still clearer than `p1 && g1 & p2 && g2`.
> Let me know what you think.
>
> Gavin
More information about the amber-spec-experts
mailing list