JEP325: Switch expressions spec

Dan Smith daniel.smith at oracle.com
Tue May 8 23:08:11 UTC 2018


Here are my notes from a pass over the spec.

Significant items:

---

SwitchStatementClause is probably too general. I don't think we want to allow arbitrary statements to occur on the RHS without braces. It's unweildy (think about a chain of if-else, for example), inconsistent with others uses of "->", and ambiguous: does "case foo -> switch (expr) { ... }" describe a switch statement or a switch expression?

I also have concerns about the heavy duplication between the specs for switch statements and switch expressions. Wasn't this design motivated by wanting to have a single, unified construct packaged in expression and statement forms?

Proposed fix: rename SwitchStatementBlock and SwitchExpressionBlock to a single SwitchBlock. Merge the two grammars, with SwitchClause being defined like SwitchExpressionClause, not SwitchStatementClause. Follow lambda expressions in stating a semantic rule that, in the statement form, the Expression be a StatementExpression.

Discuss switch blocks in a subsection of 14.11 (maybe two subsections, for arrow and colon bodies, with a certain amount of sharing). Define matching, compile-time checks, and runtime behavior. (Like lambda expressions, the treatment of Expression clauses will be context-dependent.) The remaining spec for switch statements and switch expressions should be small.

While we're at it, add 'throw' to the set of legal bodies for lambda expressions. (Or we can spin this off into a separate RFE, but I'd like to ship it in parallel.)

---

After previous discussion about enum names, I think we should relax the requirement that an enum-typed switch must use (unqualified) enum constant names. The behavior I'd like is: if the type of the selector expression is an enum type, and the pattern is an unqualified name, resolve it as a member of the enum type; otherwise, handle a ConstantExpression pattern just like any other.

(I might also drop the grammar's distinction between EnumConstantName and ConstantExpression, which is ambiguous. And I might also push this special-case logic about name resolution into Chapter 6.)

---

I have concerns about the 'break' rules; see separate thread.

---

With or without 'null', there's a good argument that the arrow clauses need a way to syntactically combine specific cases and 'default'. Where are we at on this?

---

Missing stuff (not necessarily a comprehensive list):

- 15.6, evaluation of a switch expression may throw (I hate maintaining these lists, but it's here, so we must maintain it)
- 15.12.2.1, define "potentially compatible"
- 15.12.2.5, define "more specific"
- 15.25, categorization of conditionals with switch expression operands (ugh, one more motivation to abandon the categorization scheme)
- 16, definite assignment (including how does a boolean selector/result get treated?)
- 18.2.1, inference reduction
- 18.5.2.2, searching for additional inference constraints
- 18.5.4, "more specific" inference

---

And some notes about presentational issues:

Throughout: for other specs, people have expressed interest in seeing a complete before-and-after diff. No shortcuts. (And they're probably right—it's a lot easier to see what's going on that way.) So any words that have been removed should be indicated explicitly as deletions, rather than just leaving the old words out and highlighting the new words as additions.

5.6.3 needs a better title than "numeric promotion", which is a broad term introduced in 5.6; and it needs to be properly introduced in 5.6.

The conditional expression spec should be updated to re-use the new flavor of numeric promotion.

14.11: somewhat arbitrarily, '->' is considered an "operator" while ':' is considered a "separator". Should match that terminology.

14.11: "consists of zero or more statements" is not quite right in either case. A clause block consists of clauses, which are pattern/clause body pairs. A group block consists of statement groups, which are lists of statements prefixed by a list of labels.

14.11: "It should be clear from that grammar ..." should be green

14.11: Use of the term "pattern" is premature. These are really just ConstantExpressions (plus, maybe, null). As is, we have lots of undefined concepts: When is a pattern "assignment compatible with" a type? When does a pattern "have the same value" as another?

14.11: The discussion explaining why we don't silently complete a switch when the selector is null is worth keeping, as an explanation for why, in the absense of an explicit 'case null', the statement will throw. (Better than just saying "historical reasons" or "compatibility".)

14.11 "A Java compiler is encouraged": after much discussion about exhaustiveness, I think the consensus is that we would very much not like for a Java compiler to do this. Silently doing nothing for some inputs is a feature of switch statements.

14.11: I'm pretty down on explaining features via translation to other features. It's often unclear exactly what this pseudo-code means (which JLS rules apply to it?), and there tends to be a lot of tedious work to make the pseudo-code valid (what if the statement can't complete normally?). Here it would be much clearer to just describe the run-time behavior of 'switch' in terms of clauses.

14.11 "If multiple statements are needed then a block (14.2) should be used": this is a useful illustration, but in the context of Chapter 14, probably too chatty. It's a given that a Block can be used wherever you want multiple statements. Compare the spec for the 'while' loop (14.12).

14.11: discussion about unboxing would be clearer if it were limited to a bullet defining the rule for matching a constant expression. (I might separate "constant expression of a primitive type" as a distinct case in the definition.)

14.11: "evaluates to the null"

14.11 "A case label can contain multiple patterns, and is said to match if": again, I want to push this down into a definition of "match" somewhere.

Example 14.11-1: Some further illustration is good here, but this sequencing feels very much like it was tacked on. Something like "what's the difference between two forms of switch blocks?" might be a better way to approach the discussion.

14.15, 14.16, 14.17 "immediately enclosing method, constructor, or initializer": this list should consistently include lambda bodies and switch expression blocks as well. (In the 'return' case, switch expression blocks should also be included in the rule about illegal containers.)

14.15, 14.16, 14.17 "not permitted to transfer control through a switch expression": with the change to include switch expression blocks in the other rule, there's no need for a special rule that applies to switch expressions. In fact, calling them out suggests that they are somehow treated differently than lambda bodies, when they are not. These paragraphs can be deleted.

15.15 "and the switch expression": should be green

15.29: this is probably the wrong section number; we'll have to ask Alex how much disruption he wants to tolerate.

15.29 "In contrast to a switch statement": I think the right thing to say about the contrast is this: it's impossible for the expression to complete normally without a value, so the expression must not leave out some cases.

15.29 "The rules for the selector expression": I approve of reuse, but I think this is small enough that it would be better to copy/paste the rule here.

15.29 "Can return": I don't think this requires so much discussion. Just a couple of sentences: "It is a compile-time error if the Block of a SwitchExpressionClause can complete normally. It is a compile-time error if statements of the last SwitchBlockStatementGroup can complete normally."

15.29 "the switch expression completes normally": More conventionally, "the value of the switch expression is ..."



More information about the amber-spec-experts mailing list