60. Dealing with pattern labels dominance in switch
The compiler matches the selector expression against the available pattern labels by testing the selector expression against each label starting from top to bottom (or, from the first to the last) in the exact order that we wrote them in the switch block. This means that the first match wins. Let’s assume that we have the following base class (Pill) and some pills (Nurofen, Ibuprofen, and Piafen):
abstract class Pill {}
class Nurofen extends Pill {}
class Ibuprofen extends Pill {}
class Piafen extends Pill {}
Hierarchically speaking, Nurofen, Ibuprofen, and Piafen are three classes placed at the same hierarchical level since all of them have the Pill class as the base class. In an IS-A inheritance relationship, we say that Nurfoen is a Pill, Ibuprogen is a Pill, and Piafen is a Pill as well. Next, let’s use a switch for serving our clients with the proper headache pill:
private static String headache(Pill o) {
return switch(o) {
case Nurofen nurofen -> “Get Nurofen …”;
case Ibuprofen ibuprofen -> “Get Ibuprofen …”;
case Piafen piafen -> “Get Piafen …”;
default -> “Sorry, we cannot solve your headache!”;
};
}
Calling headache(new Nurofen()) will match the first pattern label, Nurofen nurofen. In the same manner, headache(new Ibuprofen()) matches the second pattern label, and headache(new Piafen()) matches the third one. No matter how we mix the order of these label cases, they will work as expected because they are on the same level and none of them dominate the others.For instance, since people don’t want headaches they order a lot of Nurofen, so we don’t have it anymore. We represent this by removing/comment the corresponding case:
return switch(o) {
// case Nurofen nurofen -> “Get Nurofen …”;
case Ibuprofen ibuprofen -> “Get Ibuprofen …”;
case Piafen piafen -> “Get Piafen …”;
default -> “Sorry, we cannot solve your headache!”;
};
So, what happens when a client wants Nurofen? You’re right … the default branch will take action since the Ibuprofen and Piafen don’t match the selector expression.But, what will happen if we modify the switch as follows?
return switch(o) {
case Pill pill -> “Get a headache pill …”;
case Nurofen nurofen -> “Get Nurofen …”;
case Ibuprofen ibuprofen -> “Get Ibuprofen …”;
case Piafen piafen -> “Get Piafen …”;
};
By adding the Pill base class as a pattern label case allows us to remove the default branch since we cover all possible values (this is covered in detail in Problem x). This time, the compiler will raise an error to inform us that the Pill label case dominates the rest of the label cases. Practically, the first label case Pill pill dominates all other label cases because every value that matches any of the Nurofen nurofen, Ibuprofen ibuprofen, Piafen piafen patterns also matches the pattern Pill pill. So, Pill pill always wins while the rest of the label cases are useless. By switching Pill pill with Nurofen nurofen will give a chance to Nurofen nurofen, but Pill pill will still dominate the remaining two. So, we can eliminate the dominance of the base class Pill by moving its label case on the last position:
return switch(o) {
case Nurofen nurofen -> “Get Nurofen …”;
case Ibuprofen ibuprofen -> “Get Ibuprofen …”;
case Piafen piafen -> “Get Piafen …”;
case Pill pill -> “Get a headache pill …”;
};
Now, every pattern label has a chance to win.Let’s have another example that starts from this hierarchy:
abstract class Drink {}
class Small extends Drink {}
class Medium extends Small {}
class Large extends Medium {}
class Extra extends Medium {}
class Huge extends Large {}
class Jumbo extends Extra {}
This time, we have 7 classes disposed of in a multi-level hierarchy based. If we exclude the base class Drink, we can represent the rest of them in a switch as follows:
private static String buyDrink(Drink o) {
return switch(o) {
case Jumbo j: yield “We can give a Jumbo …”;
case Huge h: yield “We can give a Huge …”;
case Extra e: yield “We can give a Extra …”;
case Large l: yield “We can give a Large …”;
case Medium m: yield “We can give a Medium …”;
case Small s: yield “We can give a Small …”;
default: yield “Sorry, we don’t have this drink!”;
};
}