From scolebourne at joda.org Wed Jan 26 15:57:45 2022 From: scolebourne at joda.org (Stephen Colebourne) Date: Wed, 26 Jan 2022 15:57:45 +0000 Subject: [External] : Re: Treatment of total patterns (was: Reviewing feedback on patterns in switch) In-Reply-To: References: <06062579-A7DD-499C-839D-B77A319E38ED@oracle.com> <8B8F0C8E-45AF-48D0-ACB1-25675A898114@oracle.com> <1194660059.4382759.1643183617456.JavaMail.zimbra@u-pem.fr> <81EFA716-D027-4EE2-A269-5682FB718F86@oracle.com> <853217783.4728786.1643204710821.JavaMail.zimbra@u-pem.fr> Message-ID: Could I try again to explain why `Type t` is currently painful in switch, and propose what I believe is a new alternative approach? A year ago, Brian wrote "no one disagrees that `String s` should match all non-null instances of String". But the current proposal does in fact disagree. The reality is that `String s` can match null - it depends on what static context of the target is. My primary concern is that type patterns need to be consistent with *each other*. What I'm asking for is simply that a `Type t` pattern always means *exactly* the same thing. Right now, it does not - because the last pattern in a series of `Type t` patterns may or may not be total and you often can't tell by reading the code: switch (item) { case Integer i ... case Number n ... } Perhaps one way of helping understanding is that `Type t` is essentially an ambiguous pattern with two possible meanings - either match dynamically as per instanceof, or match against the static context of the target (and thus be total and accept null). Normally the Java compiler rejects ambiguous code (or the language designer arranges for the ambiguity not to occur). But the ambiguous code is not rejected here. IMO that is the root cause of the issue here, which remains unsolved. Proposals that tweak around the edges in switch/instanceof are not tackling that root cause. A (silly) verbose solution to this would be to add more keywords to distinguish the ambiguity, eg: switch (item) { case instanceof Number n ... case instanceof String s ... case instanceof Box(instanceof String bs) ... case instanceof Box(totalmatch Object bt) ... case instanceof Object o ... case totalmatch Object t ... } Clearly such a verbose approach won't be popular, so here is an alternative I've not seen discussed before: Looking at local variable declarations, imagine `var t` and `Type t` are both shorthand for a new local variable declaration form `var Type t`. This would be immediately beneficial for local variables, eg. var Predicate p = str -> str.length() < 2 var LocalDate date = null; (both of which require a cast today if you want to use var consistently) Now we can use this new verbose declaration form to resolve the ambiguity in pattern matching: - `Type t` - check dynamically as per instanceof, cannot be used for total matching - `var t` - use the static context and insist on a total match - `var Type t` - use the static context and insist on a total match using Type As a pattern and as a local variable declaration, `var t` can always be replaced with `var Type t`. As a pattern, `Type t` rejects null, but as a local variable declaration it allows null. When using a local variable pattern match to destructure a method return it has to be total, thus it has to use `var t` or `var Type t` (not `Type t`) Sure, it is no longer true that `var obj` and `Object obj` patterns mean exactly the same thing, but it can now be explained as part of a larger story wrt `var Object obj`. That is the novel part of this idea. The verbose example above would therefore be one of these two options, depending on your taste/needs: switch (item) { case Number n ... case String s ... case Box(String bs) ... case Box(var bt) ... case Object o ... case var t ... } switch (item) { case Number n ... case String s ... case Box(String bs) ... case Box(var Object bt) ... case Object o ... case var Object t ... } IMO, most people would use the former (Remi's C# approach, and my preferred approach, which is nice and clear). But if you want to add the actual type you can - you just have to keep the var to demonstrate totality. Anyway, thanks for listening. Stephen