If I read the JLS §8.1.6 and §9.1.4 correctly, the classes that a sealed class/interface permits, are just the direct subclasses/interfaces.
To illustrate this, consider the following example:
public sealed interface I1 permits I2, C, D { /*...*/ }
public final class C implements I1 { /*...*/ }
public final class D implements I1 { /*...*/ }
public sealed interface I2 extends I1 permits E, F { /*...*/ }
public final class E implements I2 { /*...*/ }
public final class F implements I2 { /*...*/ }
If I understand the specification correctly, I1 obviously permits C and D but not E and F (via the extends hierarchy of I2 from I1). Is this correct?
The reason I'm asking is what patterns are allowed for switch expressions of the following kind:
I1 i1 = // ...
return switch (i1) {
case C c -> "1";
case D d -> "2";
case E e -> "3"; // Can we match over E?
case F f -> "4"; // Can we match over F?
default -> "5";
};
More accurately, you can say that
CandDare in the set of permitted direct subclasses ofI1, which is a term defined in section 9.1.4. The JLS doesn't really define what "I1permitsCandD" means though.As for your switch expression, the reason why it works is two-fold. First, you are able to write a type pattern in a switch label if the type of the switch selector expression is downcast-convertible to that type.
14.11.1
14.30.3:
Obviously,
Eis downcast-convertible toI1through a widening reference conversion, becauseEimplementsI1. Note that this fact has nothing to do withpermits. It is simply a result ofE implements I2andI2 extends I1. Surely you would agree thatimplementsandextendsare transitive!Second, switch expressions need to be exhaustive. Your switch expression is always exhaustive because it has a
defaultcase. However, it is still exhaustive even without thedefaultcase.From now on, we will consider your switch expression but without the
defaultcase, because that is wherepermitsplays a role. The rules to determine whether the set of case labels you wrote are exhaustive are specified in 14.11.1.1. The important bit of your case is (this is kind of an inductive definition):"applicable permitted direct subtype of T" in your case is really just the same as "permitted direct subtype of T". You can also treat "a type T that includes an abstract and sealed class or interface named C" as the same as
T- the "includes" relationship isn't relevant to your case. WithT=I1in mind, we can start "running" this algorithm.We use the second rule first - the permitted direct subtypes of
I1areI2,CandD. Since we have aC candD din the case elements, we know that our set of case elements is exhaustive forCandD(first rule). Is it also exhaustive forI2? To determine that, we use the second rule again. The permitted direct subtypes ofI2areEandF. Using the first rule, we know that the case elementsE eandF fare exhaustive forEandFrespectively. We have now proven that that the set of case elements are exhaustive forI2,CandD, so it is exhaustive forI1, according to the second rule.So if you are talking about how switch patterns work, I think "inductive" is a better word to describe how the exhaustiveness of switch case labels are verified.