[patterns] Several patterns and guards

Guy Steele guy.steele at oracle.com
Mon Aug 14 15:54:55 UTC 2023


Or you could just require parentheses when the meaning might not be clear. And I mean _require_: allow

   case P when e:
   case P, (Q when e): 
   case (P, Q) when e: 

but NOT

   case P, Q when e: 

And if you object that

   case (P, Q) when e: 

should really mean a single tuple pattern (P, Q) plus a guard on it (I agree!), then that tells me that it was a bad idea in the first place to use commas as a separator of patterns in a case label.

—Guy

> On Aug 14, 2023, at 11:44 AM, 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, and worse, if the when clause binds to Q, then we would have to repeat the guard if we wanted `(P|Q) when e`.  We explored guards on patterns (P && e) and concluded that it was better treated as part of the switch rather than the pattern.
> 
> 
> 
>> 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