You've put your finger on the fundamental stewardship challenge here.  If we were never going to go any farther than "deconstruction patterns in switch", then we would surely do a "worse is better" hack which separates nullity from totality.  But, if we want deconstruction patterns (or Optional.of(var x), or array patterns, or collection patterns, or pattern assignment, or ...), we have to confront _nesting_, and nesting puts the connection between totality and target type and nullity right in your face.

But, Joe Java has not yet thought very much about nesting, so the answer that you get to when you work out all the details is ... counterintuitive.   As a result, we've been bombarded with (at varying levels of constructiveness) attempts to hide this complexity.  But at root, we have a choice: we can solve for the whole problem, or we can solve for the easy problems and make the hard ones even harder.  This is not an easy, or obvious, choice.

My claim is that to make pattern matching successful in Java, where we have to spend our "get users to think about something new" budget is totality.  And totality is relative to "what are you total on."

Where I think we need to shore up the story is in "how do I turn on exhaustiveness checking for statement switches."  We already have that for expression switches, and several of the holes you are worried that users will fall into come from the fact that the compiler is sometimes, but not always, type checking switches for exhaustiveness.

We've been struggling with whether there are "pattern switches" and "legacy switches", or whether we've fully generalized switch.  If the former is unavoidable, it might be possible to enforce totality checking on all but the legacy constant switches.  After all, totalizing an intentionally partial switch is simple: add a `default: break` clause.

Stepping back - my general feeling on this topic is that the audience in this mailing list have a very intimate knowledge of what a "total pattern" is, to the point that they are comfortable building on top of this definition to e.g. define null behavior of patterns. I'm a little afraid that the finer detail of totality might be lost on the average Joe developer: totality is a much more slippery concept than it seems. Sure, there is one obvious way to make your pattern total: if the target expression has type E, then add a type test pattern whose type is also E. That seems easy enough. Except that, the type of E will not always be that manifest in user code (e.g. might be the result of what javac happens to infer on Tuesdays). And, if you mix this with sealed classes, it might be possible for a switch to go from total to non-total, as new permitted subtypes are added to a sealed hierarchy. These might all be all corner cases - but I think it's this complexity which contributes to my "isn't this all too subtle?" feeling.

Obviously I'm well aware that nearly every path has been explored, and no silver bullet seems to be laying around, so... this might just be the best we can offer, and that's ok.

Cheers
Maurizio




Reply via email to