In May 17, 2021, at 4:36 PM, Brian Goetz <brian.go...@oracle.com> wrote: > > I think we've done a remarkable job at rehabilitating this monster.
+100, especially after re-reading your 2017 document. > *Someone actually suggested using the syntax "new switch", on the basis that > new was already a keyword. Would not have aged well. Yeah, and we can have as many switches as we want if we use hyphenated keywords: switch-jdk16, switch-jdk17, … It looks to me like we anticipated the design space pretty accurately in 2017. We have apparently returned to the “&&” guard syntax, after some discussion, which makes me happy. And we have avoided the need for “||” pattern connectors. There are a few roads not taken: “switch ()” with boolean case expressions has not showed itself worthy yet. The “break x;” syntax, meaning “return value x from the switch,” is obviated by doubling down on lambda-inspired “return x;”. I’d also like to point out “switch (a, b)” as a possible area of future work for switch, where the thing after “switch” is a more generalized argument expression, and the machinery of method binding could be applied to the list of values to be matched (as if they were actual arguments) and the case labels would (somehow) correspond to method formal argument lists. Having said that, I don’t think it is urgent, at all. That said, I will take the opportunity to mention a few small items of “fit and finish”, mostly anticipated in the 2017 document, which are still (IMO) useful proposals, and are currently on the back burner. 1. Allow certain simple statements after “->” without requiring “{ … }” wrappers. This is not just luxury but improves readability. I have reached for the sequence “->break;” in my IDE and been disappointed after going back to the fine print of the language. I had to write “->{break;}”, which is IMO noisy enough to be harder to read than “->break;”. As both writer and reader of code, I would rather have the use of “{}” be reserved for stuff that is truly a block or other composite (while-loop, etc.). This issue wasn’t raised with lambdas because lambdas cannot complete with control flow, but switch cases often do that. For consistency, I suggest that any type of statement that does not have sub-statements be allowed immediately after the “->”. (Of switch, and lambda if applicable.) In addition to the statement expressions already allowed, these are return, break, continue. They are also the empty statement (“;”), and assert statements. Not allowed would be declarations, labeled statements, conditionals, loops, and other nested things like try and synchronized. 2. Allow a way to add a given case to the “remainder” set, to be treated similarly to “built-in” remainder processing. Proposed syntax: “throw;” as in “case null->throw;”. (Raises the question of whether to support such a notation outside of switch, but we could just say “no”. Or spell it “throw default;” or “throw assert”.) The idea of a remainder (nulls, maybe, or new enums or sealed class subtypes) is probably useful enough that users should be given a way to opt into remainder processing explicitly. (I don’t see this in the 2017 document; we hadn’t yet generalized the idea of a “remainder”.) 3. Allow a way for imperative case logic to branch to the next applicable case. Proposed syntax: “continue switch;”, as in “case Foo f->{ if (f.bad) continue switch; }”. The purpose for this would be to allow refactoring of guards from the compact form (“case P && G:”) to a more general imperative form (“case P: if(!G) continue switch;”). Such refactoring is sometimes important in practice, if a guard G needs a temporary variable. Today’s workaround is building a helper method nearby, which hurts readability. (The “continue switch” syntax suggests other kinds of tags for break and continue, and the symmetry between switch and if/else chains suggests “continue if” as a way to branch after the next “else”. None of these require follow-up to gain value for switch.)