JDK-8223305 : Compiler Support for Switch Expressions (Second Preview)
  • Type: CSR
  • Component: tools
  • Sub-Component: javac
  • Priority: P2
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 13
  • Submitted: 2019-05-03
  • Updated: 2020-08-06
  • Resolved: 2019-06-06
Related Reports
CSR :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Summary
-------

Switch expressions were a preview feature in Java SE 12 (see [JEP 325](https://bugs.openjdk.java.net/browse/JDK-8192963) and the [CSR](https://bugs.openjdk.java.net/browse/JDK-8207241)). Based on experience with the feature, the value `break` statement which yields a value from a switch expression should be replaced by a `yield` statement.


Problem
-------

The value `break` statement is confusing to developers because it overloads the `break` with label statement. For example, `break L;` would be a labeled `break` statement in a `for` loop (transferring control out of the loop without yielding any value) but would be a value `break` statement in a switch expression (yielding the value of variable `L` as the result of the switch). In addition, the need for a value `break` statement in a switch expression is quite rare -- only when the RHS of a `case ... ->` is a block rather than an expression -- but the reuse of the `break` keyword reminds developers of the almost universal need for `break` in a switch statement; this tends to hurt understanding of switch expressions more broadly.


Solution
--------

The value `break` statement is replaced by a  new `yield` statement.

As `yield` is a valid identifier, it is not practicable to start treating it as a keyword. Even treating it as a restricted keyword leads to the potential problem that parsing a `yield` statement might require unlimited lookahead to determine if the character sequence `yield` should be tokenized as a keyword or as an identifier.

We propose a simpler strategy, building on the approach taken when adding `var` in JDK 10: `var` and now `yield` are considered *restricted identifiers*. Restricted identifiers are not valid type identifiers, i.e., you cannot declare a type called `var`  or  `yield`.

In addition we consider `yield` to be an invalid name for an unqualified method invocation. This means that the phrase `yield (3);` will be parsed as a `yield` statement and not as an unqualified invocation of a `yield` method. Invocations of methods called `yield` must be qualified, e.g., `Thread.yield();` or `this.yield();`. It is still permitted to declare an instance variable or local variable called `yield`, and to use such a variable without qualification, even in a statement context such as `yield++;` or `yield = 1;`. For such usages, the compiler is expected to perform limited lookahead and disambiguate between YieldStatement and ExpressionStatement.

Analysis of the Java SE API reveals only one method named `yield`; the occurrence of a method named `yield` in other large codebases is similarly rare. 

This update will require corresponding changes in the JDK-specific [Compiler Tree API](https://docs.oracle.com/en/java/javase/12/docs/api/jdk.compiler/com/sun/source/tree/package-summary.html).


Specification
-------------

The updated JLS changes for switch expressions is attached, and also [available online](http://cr.openjdk.java.net/~gbierman/jep354-jls-20190528.html).

The specdiff for the Trees API changes is attached, and also [available online](http://cr.openjdk.java.net/~jlahoda/8223303/specdiff.01a/overview-summary.html).
Comments
Re-read the proposed JLS changes; moving to Approved.
06-06-2019

The change in status of "yield" proposed by this CSR would be another case where a -Xlint:future flag could be helpful to warning developers of code that will become illegal of have its semantics changed in later source versions, JDK-8189145.
06-06-2019

Thanks Joe, I've uploaded and linked a fixed specdiff (specdiff.01a.zip), and added a fix version.
30-05-2019

Thanks Joe. Regarding the changes in the spec: The chief evolution (apart from a handful of minor tweaks throughout) is around the treatment of numeric promotion in section 5.6. In the spec for JEP325 we used a trick of passing in a "notional non-constant" to distinguish two different use cases of numeric promotion. Upon reflection, we decided that obfuscated what was going on. So, in the spec for JEP354, we have instead categorised the cases where numeric promotion is used into three kinds: numeric array context, numeric choice context and numeric arithmetic context (Previously the spec spoke of just a single kind: a numeric context - we are subdividing it into three). Then in the definition of numeric promotion we look at the context where it is being applied to determine which rule to pick, rather than passing in a notional non-constant or not. This significantly tidied up this section. Semantically the definitions are identical.
30-05-2019

This online specdiff is showing some odd results for comparing the visitor/scanner classes. Please explicitly indicate which fixVersion this work is intended for, presumably 13. In addition to a diff from the base JLS, it would also be helpful to have in addition at least a short semantic diff using the previous JEP 325: "Switch Expressions (Preview)" as a baseline. Yes, "replace ``break Expr;'' ``yield expr;``, but looking for the the JLS diffs for both JEPs there appear to be various evolutions beyond just the change in syntax. Moving to Provisional.
29-05-2019