[patterns] Several patterns and guards

Tagir Valeev amaembo at gmail.com
Mon Aug 14 16:04:42 UTC 2023


Hello!

On Mon, Aug 14, 2023 at 5:44 PM Brian Goetz <brian.goetz at oracle.com> wrote:
>
> So, there are two stable points here: make the where clause part of the pattern, or match it with the case label entirely.  The middle option is not stable; a case like
>
>     case P, Q when e:
>
> Is no longer clear

Exactly, it's no longer clear. This is my point: this syntax is
allowed now, and people may assume that 'when e' belongs to Q, rather
than to both patterns. Probably my feeling of English is bad, but to
me a comma looks like a stronger clause separator than 'when'.

> and worse, if the when clause binds to Q, then we would have to repeat the guard if we wanted `(P|Q) when e`.

But at least you could express this. Now, if you want a guard to be
applied to Q only, you cannot express this at all. Your options are
either to repeat the whole switch rule, or to fallback to a colon
switch.

> We explored guards on patterns (P && e) and concluded that it was better treated as part of the switch rather than the pattern.

It's ok if it doesn't belong to a pattern (e.g. cannot appear in
instanceof or inside a deconstruction). Still I'm not sure that the
middle option (guard belongs to switch label _element_) was thoroughly
explored. Or probably I've missed the discussion (in this case, I
would be glad if you pointed me on it). Note that it was irrelevant
until unnamed variables were introduced, as several patterns in the
label were syntactically incorrect.

With best regards,
Tagir Valeev.

>
>
>
> > On Aug 14, 2023, at 8:28 AM, Tagir Valeev <amaembo at gmail.com> wrote:
> >
> > I don't think that my example is contrived. Let's think of it from
> > another angle. Are multiple patterns in the same switch label useful
> > or contrived? If not useful, then let's disable them completely. If
> > useful, then the next question: are guards with multiple patterns
> > useful or contrived? Can you imagine a case when the single guard for
> > the whole label will be useful (provided that we cannot declare any
> > variables)? I'm not quite sure that a non-contrived example is
> > possible. So probably we should disable guards with multiple patterns
> > completely?
> >
> > My point is that having a separate guard per pattern is much more
> > useful and less confusing than having a single guard for all patterns.
> > You may convince me that I'm wrong by providing not-so-contrived
> > examples.
> >
> > By the way, the following colon-style switch looks supported (though
> > buggy again, reported JDK-8314226):
> >
> > void test(Object obj) {
> >  switch (obj) {
> >    case Integer _ when ((Integer) obj) > 0:
> >    case String _ when !((String) obj).isEmpty():
> >      System.out.println(obj + ": Positive number or non-empty string");
> >      break;
> >    default:
> >      System.out.println("other");
> >  }
> > }
> >
> > And it looks like there's no way to express the same with an
> > arrow-style switch, or even replace adjacent cases with comma (which
> > is possible for other cases).
> >
> > With best regards,
> > Tagir Valeev.
> >
> > On Mon, Aug 14, 2023 at 5:04 PM Brian Goetz <brian.goetz at oracle.com> wrote:
> >>
> >> While we could certainly do this, I think the cost-benefit runs in the wrong direction here.  This sort of thing is better expressed as an if, and that’s fine.  (I think you’ll agree that this example is a little bit contrived.).
> >>
> >>> On Aug 14, 2023, at 5:15 AM, Tagir Valeev <amaembo at gmail.com> wrote:
> >>>
> >>> Hello!
> >>>
> >>> Currently, when the switch label contains several patterns, only one
> >>> guard could be declared, which is applied to all the patterns at once.
> >>> In other words, the following code is not possible:
> >>>
> >>> void test(Object obj) {
> >>> switch (obj) {
> >>>   case Integer _ when ((Integer) obj) > 0,
> >>>        String _ when !((String) obj).isEmpty()
> >>>           -> System.out.println("Positive number or non-empty string");
> >>>   default -> System.out.println("other");
> >>> }
> >>> }
> >>>
> >>> Does it make sense to lift this restriction? Probably it could be
> >>> useful to declare separate guards? Ideally it should be possible to be
> >>> able to declare a pattern variable, which is visible inside the
> >>> pattern-specific guard only (but not inside the rule body).
> >>>
> >>> Another confusing thing here:
> >>>
> >>> void test(Object obj) {
> >>> switch (obj) {
> >>>   case Integer _,
> >>>        String _ when !((String) obj).isEmpty()
> >>>           -> System.out.println("Number or non-empty string");
> >>>   default -> System.out.println("other");
> >>> }
> >>> }
> >>>
> >>> Now, the guard is applied even if obj is Integer (resulting in
> >>> ClassCastException). This is not quite evident from the code. We may
> >>> say that 'when' precedence is lower than ',' precedence, but people
> >>> may expect the opposite. Should not we reconsider this and make guard
> >>> a part of the lebel element, rather than the part of the whole label?
> >>>
> >>> With best regards,
> >>> Tagir Valeev.
> >>
>


More information about the amber-spec-experts mailing list