[pattern-switch] Guards
Brian Goetz
brian.goetz at oracle.com
Sun Jan 10 21:41:33 UTC 2021
>> I agree such a move would be poor. That was my motivation for
>> suggesting & for "pattern conjunction" instead of &&; to relegate
>> these concerns to irrelevance. So
>>
>> if (x instanceof P & X)
>>
>> says X is a pattern and we're testing x against the composite pattern
>> P AND X, and
>>
>> if (x instanceof P && X)
>>
>> says X is a boolean expression.
>
> And I am saying, yes we can do that and make it work, but only by
> violating Java's ancient implicit design rule that operator precedence
> obeys a total order.
Ah, now I get it. I'm looking at what happens on the right side, and
you're pointing out a problem before we even get there, which is:
instanceof is going to gobble the first clause of the conjunction,
whether the conjunction is joined with & or &&. Got it.
> If I understand correctly, your proposal is that
>
> if (x instanceof P & X) means the same as if (x instanceof
> (P & X)) if X is a pattern
>
> but
>
> if (x instanceof P & X) means the same as if ((x instanceof
> P) & X) if X is an expression
>
> (which has always been true, and I’m assuming you are not proposing a
> big, incompatible change here).
Well, now that you put it that way, it doesn't sound as good. But,
let's pull on that string.
> That would mean that you have to commit to a grammar in which patterns
> can in fact be distinguished from expressions.
This would be great, and not only for compilers -- it would be good if a
human were not confused by "is that a pattern or an expression." The
last time we looked at this, we had identified three sources of
ambiguity, two of which we've banished at least temporarily:
1. A bare type as a pattern. At first, we tried to retcon `T` in `x
instanceof T` as being a pattern with no bindings. But among other
problems, that means that any bare identifier might be either a pattern
or an expression. We addressed this by adjusting the grammar around
`instanceof`, to say there are two forms: `x instanceof Type` and `x
instanceof Pattern`.
2. Constants. We initially thought constant patterns were a
no-brainer, but then it is really hard to tell when `foo(0)` or
`Bar(null)` is a pattern or an invocation. We have tentatively
addressed this by just not doing constant patterns, or, if we want to do
them later, commit to coming up with a less ambiguous syntax (such as
`== 0` for a constant pattern.) But, the more I think about constant
patterns, the weaker they seem as a feature; they don't obviate the need
for guards, and the set of patterns that can use constants instead of
guards is pretty small. (C# went down the road of relational patterns
such as `> 0`, but I'm not sure how much of a dent this makes either.)
3. Nilary deconstruction patterns. The remaining ambiguity (as far as
I can tell) is `Foo()`; this could be an invocation or a match to a
nilary deconstruction pattern. (This stems in part from making the
binding for the narrowed target optional; you can say `Foo(var x) f`,
but the `f` is optional, because much of the time you don't need it.)
Perhaps if we said that the narrowed target is required if there are no
nested patterns, then we could banish this ambiguity.
So, we don't yet have the grammar where patterns are fully
distinguishable, but we almost do. So one path here is to finish that job.
For sake of exposition, I'll use &&& to mean "pattern and", since I want
to separate the parsing details from the semantics.
> Note that if that latter fact is true, then you don’t need to say
>
> case P(var x) & true(x > 0):
>
> It should suffice to say
>
> case P(var x) & x > 0:
The essence of that approach is that we can treat any (boolean)
expression as a pattern (which is not out of the question.) Because, we
may want to keep matching more stuff if the guard succeeds:
case P(var x) &&& true(x > 0) &&& Q(var y):
| |
-------------------------------------
|
one big pattern
So I think you're proposing:
- Find a grammar where patterns and expressions are disjoint
- Treat any (boolean) expression as a pattern when conjoined with &&&
(or however we denote pattern conjunction.)
We flirted with this briefly in the past but got stuck on point (3) above.
Returning to the syntactic choice of conjunction, I'm also worried about
the human concern of reusing &&, since we expect
if (x instanceof P && somethingElse) { ... }
to be common, and it would be nice if users didn't have to work so hard
to tell whether somethingElse was another pattern, or another clause.
(Or worse, if there are many intermediate clauses, it surely won't be
obvious if the last clause is a pattern.) Using && inside of if
statements is really common, so I don't want to invite this ambiguity,
which is why I was thinking about &, which is less likely to elicit such
confusion, but still may not work well enough.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210110/9656d1ac/attachment.htm>
More information about the amber-spec-experts
mailing list