Apart from what have said about letting grobble to fully access to the 
bindings, 
i think that using parenthesis to call grobble here is already too much. 

case Foo(var x) when x > y 
is far more readable than 
case Foo(var x) when (x > y) 
because for a pattern the parenthesis describes a notion of ownership, you are 
describing the content of the type using a destructuring pattern, while the 
second pair of parenthesis is a kind of method call. 

Having two pairs of parenthesis with two complete different meanings is 
something is hope you can avoid, at least for the simple cases. 

Rémi 

> De: "Brian Goetz" <brian.go...@oracle.com>
> À: "amber-spec-experts" <amber-spec-experts@openjdk.java.net>
> Envoyé: Vendredi 5 Mars 2021 20:14:01
> Objet: Guards

> Let me try and summarize all that has been said on the Guards topic.

> #### Background and requirements

> For `instanceof`, we don't need any sort of guard right now (with the patterns
> we have); we can already conjoin arbitrary boolean expressions with `&&` in 
> all
> the contexts we can use `instanceof`, because it's a boolean expression. (This
> may change in the future as patterns get richer.) So we can already express 
> our
> canonical guarded Point example with

> if (p instanceof Point(var x, var y) && x > y) { ... }

> with code that no one will find confusing.

> For switch, we can't do this, because case labels are not boolean expressions,
> they're some ad-hoc sub-language. When the sub-language was so limited that it
> could only express int and string constants, this wasn't a problem; there was
> little refinement needed on `case "Foo"`.

> As we make switch more powerful, we face a problem: if the user drifts out of
> the territory of what can be expressed as case labels, they fall off the cliff
> and have to refactor their 50-way switch into an if-else chain. This will be a
> really bad user experience. Some sort of escape hatch to boolean logic buys us
> insurance against this bad experience -- as long as you can express your
> non-pattern criteria with a boolean expression (which is pretty rich), you
> don't have to leave switch-land.

> So we took as our requirement:

> Some sort of guard construct that is usable in switch is a forced move.

> #### Expressing guards in switch

> There are several ways to envision guards:

> - As patterns that refine other patterns (e.g., a "true" pattern)
> - As an additional feature of "case" in switch (e.g., a "when" clause)
> - As an imperative control-flow statement usable in "switch" (e.g., 
> "continue")

> We've largely rejected the third (even though it is more primitive than the
> others), because we think the resulting code will be much harder to read and
> more error-prone. We've bounced back and forth between "let's nail something 
> on
> the side of switch" and "let's let the rising pattern tide lift all 
> conditional
> constructs."

> Other languages have demonstrated that guards in switch-like constructs are
> viable.

> The argument in favor of nailing something on the side of switch is that it is
> pragmatic; it is immediately understandable, it raises the expressivity of
> `switch` to where `if` already is, and it solves the immediate requirement we
> have in adding patterns to switch.

> The argument against is that it is not a primitive; it is dominated by the
> option of making patterns richer (by adding boolean patterns), it is weak and
> non-compositional, and overly specific to switch. (It is possible to make
> worse-is-better arguments here that we should do this anyway, but it's not
> really possible to seriously claim better, despite attempts to the contrary.)

> #### Interpreting the feedback

> The JEP proposes a powerful and compositional approach:

> - true/false patterns that accept arbitrary boolean expressions (and which
> ignore their target);
> - combining patterns with a pattern-AND combinator

> On the one hand, this is a principled, orthogonal, compositional, expressive,
> broadly applicable approach, based on sensible primitives, which will be 
> usable
> in other contexts, and which anticipate future requirements and directions.

> On the other hand, there has been a pretty powerful emotional reaction, which
> could be summarized as "sorry, we're not ready for this degree of generality
> yet with respect to patterns." This emotional reaction seems to have two
> primary components:

> - A "who moved my cheese" reaction to the overloading of `true` in this way --
> that `true` seems to be, in everyone's mind, a constant, and seeing it as a
> pattern is at least temporarily jarring. (This may be a temporary reaction, 
> but
> there's still a cost of burning through it.)

> - A reaction to "borrowing & from the future" -- because the other use cases 
> for
> &-composition are not obvious or comfortable yet, the use of &-composition
> seems foreign and forced, and accordingly engenders a strong reaction.

> The former (which I think is felt more acutely) could be addressed by taking a
> conditional keyword such as `when` here; ad-hoc "focus" research suggests the
> negative reaction here is lower, but still there.

> The latter is, I think, the more linguistically significant of the two; even
> though there is a strong motivation for & coming down the pike, this is not 
> the
> gentle introduction to pattern combination that we'd like, and developer's
> mental models of patterns may not be ready. Patterns are still new, and we'd
> like for the initial experience to make people want more, rather than scare
> them with too much up front.

> #### Options

> I suspect that we'd get a lot of mileage out of just renaming true to 
> something
> like "when"; it avoids the "but that's not what true is" reaction, and is
> readable enough:

> case Foo(var x) & when(x > 0):

> but I think it will still be perceived as "glass half empty", with lots of 
> "why
> do I need the &" reactions. And, in the trivial (but likely quite common, at
> least initially) case of one pattern and one guard, the answers are not likely
> to be very satisfying, no matter how solidly grounded in reality, because the
> generality of the compositional approach is not yet obvious enough to those
> seeing patterns for the first time.

> I am not compelled by the direction of "just add guards to switch and be done
> with it", because that's a job we're going to have to re-do later. But I think
> there's a small tweak which may help a lot: do that job now, with only a small
> shadow of lasting damage:

> - Expose `grobble(expr)` clauses as an option on pattern switch cases;

> - When we introduce & combination (which can be deferred if we have a switch
> guard now), plan for a `grobble(e)` pattern. At that point,

> case Foo(var x) grobble(x > 0):

> is revealed to be sugar for

> case Foo(var x) & grobble(x > 0):

> As as bonus, we can use grobble by itself in pattern switches to incorporate
> non-target criteria:

> case grobble(e):

> which is later revealed to be sugar for:

> case Foo(var _) & grobble(e):

> The downside here is that in the long run, we have something like the C-style
> array declarations; in the trivial case of a single pattern with a guard, you
> can leave in the & or leave it out, not unlike declaring `int[] x` vs `int
> x[]`. Like the "transitional" (but in fact permanent) sop of C-style
> declarations, the "optional &" will surely become an impediment ("why can I
> leave it out here, but not there, that's inconsistent").

> All that said, this is probably an acceptable worse-is-better direction, where
> in the short term users are not forced to confront a model that they don't yet
> understand (or borrow concepts from the future), with a path to
> sort-of-almost-unification in the future that is probably acceptable.

Reply via email to