I like this. That was my point: such things should be explicit. Both total-switch and (total B) cast look very clean and natural to me.
With best regards, Tagir Valeev. On Sat, Jan 23, 2021 at 12:27 AM Brian Goetz <brian.go...@oracle.com> wrote: > > I want to pick up on this thread, now that we may have some more fire to add > to it, and we've all had some time to think about it. > > - The main technical debt that we piled up when doing switch expressions is > that switch expressions must be total, whereas switch statements are not. > There's nothing wrong with partial switch statements, but there's a middle > case where we have a switch statement that we _intend to be_ total, and it > would surely be nice to get the compiler to type-check that assumption for us. > > - Separately, we have cases where we know in our hearts that a blind cast > will work, but have no way to tell that to the compiler. For example: > > sealed interface A permits B { } > sealed class B implements A { } > ... > A a = ... > B b = (B) a; > > In this code, our A cannot be anything but a B; there is only one concrete > class in the hierarchy. We have talked about allowing this without a cast > (which I think is OK, and DanH agrees with below, but is not my main point > here), but the cast here to B is a lot like a switch that I intend to be > total, but for which the compiler does not type check this assumption. It > would be nice to get some type checking behind it, in case, say, someone else > adds another subtype of A. > > - Separately separately, in the discussion about nulls in patterns, there is > some concern that it is not always obvious when a nested pattern is total. > Again, we have a case where there might have been some design intent, but it > is (a) not type-checked and (b) not obvious to readers of the code, and it > might be nice to capture this intent. > > I think these things are the same feature. So what if: > > total-switch (x) { ... } // or switch-total > > meant "I assert this switch is total, please error if it is not." And > > b = (total B) a; > > meant "I assert this case is total, please error if not." And > > case Foo(total Bar x) > > meant "I assert that this nested pattern is total, please error if not." > > In all cases, this doesn't change the semantics, it doesn't *make* anything > total -- it just provides a way to capture the design intent in a way the > compiler can type-check it. > > > On 11/24/2020 10:35 AM, Brian Goetz wrote: > > > > I agree Brian's really onto something with suggesting the totality question > is the same for the two features. I'm in favour of going even further and > removing the cast to allow = to do double duty here for sealed types rather > than introducing new syntax for it. The new syntax ("__ construct" or > "(total BarImpl)") highlights "this is different" and I'm not sure we need to > do that for sealed types. Letting ='s do the work feels like a better form > of auto-boxing where javac does the compile-time analysis and errors out for > non-total cases or inserts the required total cast for the user. This gives > both compile time checking and runtime safety without needing to beat the > reader over the head about it. > > We want to make it easier to read & write correct code - pushing the analysis > of totality for sealed types into javac does both for us. > > > To connect to the mail that crossed with Dan's, Dan is voting for: > > - Allowing `P = e` when P is optimistically total on the static type of `e` > > In reviewing the discussions on this over the past few years, what I'm seeing > is that this requires a certain degree of "getting comfortable" with it. At > first, locutions like this seemed woefully imprecise, and everyone got > nervous, but over time, people have been coming around to it. The > "bargaining" stage involves things like "stick `let` in front of it", "allow > it for locals, but not method parameters", and "require it to be strictly > total (or total only with null remainder.") Over time, many of these > proposed restrictions are seen to be "bargaining" with change, and we get > comfortable with them. > > Dan's observation here is that, with a suitable interpretation of total > pattern match as a generalization of local declaration, we don't need the > cast at all, so we sidestep the question. > > That said, even if we do that, we're not totally out of the woods, for a > minor and major reason. > > The minor reason is the use in expressions. Suppose we have a context where > we are limited to expressions, not statements (e.g., field initializers, > constructor arguments, etc.) or where we just don't want to use a statement > for aesthetic reasons. We still have to use a cast in these cases, and the > cast is still blind. But that's minor. > > THe major reason is that we still don't have a way to say "this statement > switch is total, please typecheck that for me." I don't see a way we get to > inferring this, which means we need some syntax. Being able to reuse the > same syntax in other contexts (e.g., casts) may reinforce it in both places. > > >