Guards redux
Brian Goetz
brian.goetz at oracle.com
Wed Mar 10 15:02:10 UTC 2021
This feels like we landed in a good place. It preserves the underlying
goal of the original approach -- that we can compose patterns with
patterns, and patterns with boolean expressions, and doesn't require
nailing bags onto switch (yay). The main difference is that it creates
a distinguished "guarded pattern" operator rather than asking users to
compose guarded patterns from an expression-to-pattern operator and
pattern-AND.
The main objections to the `P & true(e)` approach were the aesthetic
reaction to this use of `true` (which was one of those
first-five-minutes reactions, and people might well have gotten over it
in the next five minutes), and the more serious discoverability problem
of having to compose two (currently unfamiliar) features to get guarded
patterns. The current proposal seems a lower energy state, while
deriving from the same basic principles.
FTR, the key observation that broke the jam was the observation that, if
we treat & and && as:
(&) :: Pattern -> Pattern -> Pattern
(&&) :: Pattern -> Expression -> Pattern
we can, with parentheses, achieve arbitrary orderings of patterns and
guard expressions, and are not forced to push all guards to the end
(which was where we got stuck the last time we looked at &&.)
On 3/10/2021 9:47 AM, Gavin Bierman 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!
>
> 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
>
> ConditionalOrPattern:
> : ConditionalAndPattern
> : ConditionalOrPattern `|` ConditionalAndPattern
>
> ConditionalAndPattern:
> : PrimaryPattern
> : ConditionalAndPattern `&` PrimaryPattern
>
> PrimaryPattern:
> : TypePattern
> : RecordPattern
> : ArrayPattern
> : `(` Pattern `)`
>
> Guard:
> : AssignmentExpression
>
> Along with the following change to the grammar for instanceof:
>
> InstanceofExpression:
> : RelationalExpression `instanceof` ReferenceType
> : RelationalExpression `instanceof` PrimaryPattern <-- Note!
>
> 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.
>
> Let me know what you think.
>
> Gavin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210310/6bc25d9d/attachment.htm>
More information about the amber-spec-experts
mailing list