Next up for patterns: type patterns in switch
forax at univ-mlv.fr
forax at univ-mlv.fr
Wed Aug 12 19:57:41 UTC 2020
> De: "Brian Goetz" <brian.goetz at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "Guy Steele" <guy.steele at oracle.com>, "John Rose" <john.r.rose at oracle.com>,
> "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Envoyé: Mercredi 12 Août 2020 16:29:50
> Objet: Re: Next up for patterns: type patterns in switch
>>> So, who is bothered by the fact that case #3 gets Box(null), and case #6 gets
>>> Bag(null)? Anyone? (And, if not, but you are bothered by the lack of totality
>>> on the true catch-alls, why not?)
>> I'm bothered if the pattern are not declared as total
> That's too bad, because there was a proposal that might work (`default` enables
> type checking for totality on switches) and now you want to escalate it to
> something that "totally" does not work (`default` makes _patterns_ total.)
>> and i believe Stephen Colebourne on amber-dev is proposing exactly the same
>> rules.
in fact, it's not exactly the same rules, because Stephen rules allows "case Foo foo" and "default Foo foo" in the same switch, while i think that "case Foo foo" should be flagged as an error if the pattern is total.
> You should read my long explanation to Stephen over there. TL;DR: this is not
> engaging with half of what pattern matching is really for, and so is coming to
> the wrong answer. Totality needs to be a property of the pattern, not the
> context -- otherwise, the same pattern in switch doesn't mean the same pattern
> in instanceof, and each construct needs its own totality hacks. This is just
> another bad variant; worse, in fact, that the "any x" proposal.
I agree that totality should be a property of a pattern not of a case, like currently "default" does.
As you said, using "any" is better because it's per pattern and not per case.
Continuing with the "default" keyword even if we may come with a better keyword latter, we are back to what Guy was proposing, "case default var x" or inside a nested-pattern "case Box(default var x)",
default being the keyword saying it's total thus allows null.
> Having total patterns is very important; if I have:
> record Bag<T>(T t) implements Container<T> { }
> record DoubleBox<T>(InnerBox<T> x) implements Container<T> { }
> record InnerBox<T>(T x) { }
> and I do
> switch (container) {
> case DoubleBox(InnerBox(var x)): ...
> }
> the outer pattern is not total on Containers (doesn't match Bag), but the inner
> pattern is once we match DoubleBox. I want to match all DoubleBoxes, and
> destructure their contents. If I try to wedge totality into patterns through
> switch case modifiers, then (a) the totality is all or nothing, at all levels,
> and (b) what do I do when I want to refactor that switch into a chain of
> instanceof operations? Then there's no way to express the pattern I want!
> Totality must be a property of the pattern, and then we can define
> (orthogonally, please) how the patterns interact with the enclosing construct.
Right, it should be
switch (container) {
case DoubleBox(InnerBox(default var x)): ...
}
> I think the mistake that is dragging you down the wrong road is the assumption
> that pattern matching is always about conditionality. But destructuring is just
> as important as conditionality. Sometimes a pattern is total (on a given type),
> and sometimes its not, but in all cases it describes the same destructuring.
> What was wrong with the "just use case var x" proposal is that it said "you
> can't use destructuring when you're total, because a null might sneak along for
> the ride", which was just mean.
I agree destructuring is just as important as conditionality and those two things should be orthogonal.
But i still think having a keyword to signal that a pattern (not a case) is total is better than letting people guess.
Rémi
More information about the amber-spec-observers
mailing list