---

5.5: There's this "downcast compatible" notion that was apparently introduced 
with instanceof pattern matching. It means a cast is legal and not unchecked. Ok. But—not 
all legal casts are downcasts, right? It's pretty confusing to use a term that suggests 
that they are.

I tripped over this a few times as well, until I just memorized what "DC" meant.  A better name is welcome.

6.3.3.1: Maybe someday we'll have expressions nested in patterns, but for now 
isn't it meaningless to ask whether a pattern variable is in scope within 
another part of the same pattern?

This may be leftover from when we had guarded patterns `P && e`, where `e` was part of the pattern?


- It's weird that 'null' is the one case constant that can't come after a 'default', 
given that 'null' is the one value that can't be handled by a 'default'. :-) Since we 
have to allow other case constants after 'default' anyway, I think it's best to allow 
'null' as one more. ("default dominates everything except constants" is a rule 
I can remember.)

I suspect that this can be simplified further, and will have to be anyway when we do underscore (since we will be allowing multiple patterns on a single case.)

14.11.1: I don't think we prevent this scenario:

switch (obj) { case String s: case Object o: }

The rules about duplicate pattern labels apply to "a statement is labeled...". 
There's no labeled statement here.

I think we should probably prohibit this, for the same code hygiene reason that 
we prohibit it before a statement group that doesn't try to use any of the 
variables.

(This would not be a legal switch expression, because switch expressions can't 
fall out. But enhanced switch statements can, as long as they're exhaustive.)

Let's be clear about why we'd be prohibiting this.  Arguably, this could be OK as long as there is no use of either `s` or `o` here. But that seems pretty useless.

The basis for disallowing should be that you can't fall into, or out of, a case label that declares a pattern variable.

14.11.2: Design suggestion: rename "enhanced switch" to "pattern switch", define it as 
only those switches that make use of patterns, and don't worry about the remaining "switch with new 
features" corner cases. It's just such an important concept that I think there's a benefit to making the 
distinction really clean and obvious. E.g., asking someone new to Java to memorize the ad hoc set of types 
that don't demand exhaustiveness seems unhelpfully complicated.

(Corner cases I'm thinking about: want to use a null constant but not be 
exhaustive? Fine. Want to have an Object input type but an empty switch body? 
Pointless, but fine. Etc.)

I think the motivation here is that we want to minimize the surface area of non-exhaustive switches, by quarantining the "need not be exhaustive" to those that would have compiled under Java 8. "Switches must be exhaustive, except for statement switches over T1..Tn with all constant labels."

14.11.3, 15.28.2: Opinionated take: we're continuing to throw ICCE when an 
unmatched enum constant slips through a switch, because it would be a 
(behaviorally) incompatible change to throw something else. Meanwhile, 
unmatched sealed classes get a MatchException. I think there are a tiny number 
of people who would notice if we changed from ICCE to MatchException for enums 
too, and a lot more people who will have to cope with the historical baggage 
going forward if we don't. We should just standardize on MatchException.

Probably better, it's a small incompatibility.  No one could be relying on the ICCE...

14.14.2: I'm sure there's been some discussion about this already, but the use 
of MatchException for nulls in 'for' loops but NPE for nulls in switches also 
seems like a sad historical wart. What's wrong with an NPE from a 'for' loop?

I think if the RHS of the foreach loop is null, we should NPE (as before.)  But if one of the _elements_ of the RHS array/iterable is null, then we should ME on the record pattern.  (Otherwise we have a sharp edge between a top-level record pattern and a nested record pattern.)

14.30.1: Parenthesized patterns are no fun for a spec writer. :-) Are they 
actually useful? I'm not sure I've seen an example demonstrating what they're 
for. (The JEP only talks about them abstractly.)

They were added when we were doing guarded patterns and never took them out.  They will be useful again when we have & and | for patterns; right now they're just taking up space.

14.30.1, 14.30.2: I'm not sold on *any patterns*, *resolved patterns*, and 
*executable switch blocks*.

The semantics are fine—some type patterns will match null, others will not. But it seems 
to me that this can be a property of the type pattern, one of many properties of programs 
that we determine at compile time. No need to frame it as rewriting a program into 
something else. (Compare the handling of the '+' operator. We don't rewrite to a 
non-denotable "concatenation expression".)

Concretely:
- The pattern matching runtime rules can just say "the null reference matches a type 
pattern if the type pattern is unconditional".
- We can make it a little more clear that a type pattern is determined to be 
unconditional, or not, based on its context-dependent match type (is that what 
we call it?)

For a *compiler*, it will be useful to come up with an encoding that preserves the 
compile-time "unconditional" property in bytecode. But that's a compiler 
problem, not something JLS needs to comment on.

It is a property of the pattern *and the type being matched*.  We tried writing it the other way and it was not necessarily better....

14.30.3: A record pattern can't match null, but for the purpose of dominance, 
it's not clear to me why a record pattern can't be considered unconditional, 
and thus dominate the equivalent type pattern or a 'default'.

Unconditional means "no runtime checks"; it's like a static cast for which we don't emit a checkcast.  Exhaustive means "satisfies the type system, but might have bad values" (null, novel enum constants, novel subtypes, at any level in the tree.)

Reply via email to