----- Mail original ----- > De: "Brian Goetz" <brian.go...@oracle.com> > À: "Remi Forax" <fo...@univ-mlv.fr>, "amber-spec-experts" > <amber-spec-experts@openjdk.java.net> > Envoyé: Lundi 24 Août 2020 20:57:03 > Objet: Re: switch: using an expicit type as total is dangerous
>> 2/ using an explicit type for a total type is a footgun because the semantics >> will change if the hierarchy or the return type of a method switched upon >> change. > > Sorry, I think this argument is a pure red herring. I get why this is > one of those "scary the first time you see it" issues, but I think the > fear has been overblown to near-panic proportions. We've spent a lot of > time talking about it and, the more we talk, the less worried I am. good for you, the more i talk about it, the more i'm worried because you don't seem to understand that having the semantics that change underneath you is bad. > > The conditions that have to combine for this to happen are already > individually rare: > - a hierarchy change, combined with > - enough use-site type inference that is not obvious what the type > dependencies are, combined with > - null actually being a member of the domain, combined with > - users not realizing null is a member of the domain. nope, you don't need a hierarchy change, changing the return type (as noticed by Tagir) and null being part of the domain is enough. > > Then, for it to actually be a problem, not only do all of the above have > to happen, but an unhandled null has to actually show up. > > Even then, the severity of this case is low -- most likely, the NPE gets > moved from one place to another. nope see below > > Even then, the remediation cost is trivial. for having remediation, as a user you have to first see the change of semantics, but you don't. Ok, let's take an example, i've written a method getLiteral() Number getLiteral(String token) { if (token.equals("null")) { return null; // null is part of the domain } try { return Integer.parseInt(token); } catch(NumberFormatException e) { return Double.parseDouble(token); } } and a statement switch in another package/module switch(getLiteral(token)) { case Integer -> System.out.println("Integer"); case Double -> System.out.println("Double"); case Number -> System.out.println("null"); } but now i change getLiteral() to add string literal Object getLiteral(String token) { if (token.equals("null")) { return null; // null is part of the domain } if (token.startsWith("\"") { return token.substring(1, token.length() - 1); } try { return Integer.parseInt(token); } catch(NumberFormatException e) { return Double.parseDouble(token); } } If i only recompile getLiteral(), and run the code containing the switch, i get a ICCE at runtime because the signature of getLiteral() has changed, which is good, but if i now recompile the switch, the code compiles without any error but with a different semantics, duh ? Using "case var _" as the last case at least keep the same semantics, using "default Number" does not compile. [...] Rémi