[patterns] Several patterns and guards
Brian Goetz
brian.goetz at oracle.com
Mon Aug 14 15:44:37 UTC 2023
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