Issue
Given a sealed hierarchy as below
sealed interface Shape permits Rectangle, Square
record Rectangle() implements Shape
record Square() implements Shape
Since Rectangle & Square are records, it inherently makes the whole hierarchy non-extensible i.e. no more subclasses are allowed any more.
Starting JDK 21, pattern matching for switch enforces switch to be exhaustive either by covering all possible case or by providing a default case to cover the remaining.
Thus, for below switch under what circumstances default case would be executed as all possible combinations are covered and why is it even permitted?
switch (shape) {
case Rectangle r -> // do something with r;
case Square sq -> // do something with sq;
case null -> // shape could be null
default -> // WHY is this permitted when all possible cases are covered already??
}
P.S.: The sealed hierarchy definitely can evolve, but when that happens compiler will automatically flag the switch to upgrade itself too.
Solution
The sealed hierarchy definitely can evolve, but when that happens compiler will automatically flag the switch to upgrade itself too.
This is not true. You seem to be assuming that both the switch statement and the records/sealed interfaces will always be compiled together. Of course, this will likely be true in most practical situations, but it is not always true. You can compile the sealed interfaces and records without recompiling the switch statement.
For example, suppose the types are all in separate .java files named with their names, so Shape.java, Rectangle.java, Square.java, while the switch statement is in the main method in Main.java.
First, I compile all the Java source files I have, and produces .class files for every .java file.
Then, suppose I change Shape.java to:
sealed interface Shape permits Rectangle, Square, Triangle
and added a Triangle.java file.
After that, I will compile just the records and the sealed interface, without compiling Main.java. This is possible, because they don't depend on Main.java.
Finally, I run java Main. This will run the Main.class file, which doesn't know about the new Triangle class, because it was compiled before I added Triangle.
This is where the default branch will be executed, or if you don't have a default branch, this is where a MatchException will be thrown.
(Note that the MatchException part only applies to switch expressions and the enhanced switch statements, like the one in your question. Non-enhanced switch statements simply don't do anything if no cases match.)
See also Execution of a switch Statement and Run-Time Evaluation of switch Expressions in the Java Language Specification.
Answered By - Sweeper
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.