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.