Monday, September 2, 2019

Sealed Types: JLS Changes (Draft)

Following the recent announcement of the candidate JEP on sealed types (preview), Gavin Bierman's message "Draft JLS spec for sealed types" on the OpenJDK amber-spec-experts mailing list announces "a draft language spec for sealed types" and provides a link to that draft. That message also states, "This spec doesn’t yet contain details on binary compatibility (Chapter 13) - to appear in the next draft."

In this post, I highlight some of the proposed changes to the Java Language Specification (JLS) for sealed types. It is important to keep in mind the tentativeness of these proposed changes: this is a draft of proposed JLS changes for a preview feature associated with a candidate JDK Enhancement Proposal (JEP).

With the caveats just outlined in mind, here are some of the interesting currently proposed changes to the JLS for sealed types with new text, deleted text, and typos highlighted differently.

  • Chapter 8: Classes
    • New sentences: "The degree to which a class can be extended can be explictly controlled. A class may be declared sealed, in which case there is a fixed set of classes that directly extend the sealed class."
    • Two new class modifiers spelled out in Section 8.1.1 ("Class Modifiers"): "abstract static sealed non-sealed final strictfp"
    • New sentence in Section 8.1.1: "It is a compile-time error if a class declaration has more than one of the class modifiers sealed, non-sealed and final."
    • Title of Section 8.1.1.2 changes to "sealed, non-sealed, and final Classes"
    • Three new sentences in renamed Section 8.1.1.2:
      • "A class can be declared sealed when it is useful to restrict its subclasses to a fixed set of classes."
      • "In certain circumstances, a class can be declared non-sealed to allow unrestricted subclasses."
      • "It is a compile-time error if a class that does not extend a sealed class or implement a sealed interface is declared non-sealed."
    • The entire section 8.1.6 ("Permitted subclasses") is new [former Section 8.1.6 is proposed to be Section 8.1.7] and here are just a few of its sentences:
      • "A sealed class can restrict its subclasses to a fixed set of classes. The permitted subclasses of a sealed class C are declared in a permits clause. A sealed class C may have an explicitly declared permits clause, which provides a non-empty list of the permitted subclasses of C."
      • "It is a compile-time error if a class is declared both abstract and sealed, and has no permitted subclasses, because the implementation of such a class could never be completed."
      • "It is a compile-time error if a class that is not sealed has a permits clause."
  • Chapter 9: Interfaces
    • New sentence: "Unlike a class, an interface cannot be declared final. However, an interface may be declared sealed, in which case it specifies a fixed set of classes and interfaces that directly implement or extend the sealed interface."
    • Two new interface modifiers spelled out in Section 9.1.1 ("Interface Modifiers"): "abstract static sealed non-sealed strictfp"
    • Section 9.1.1.3 is proposed as a new section called "sealed and non-sealed Interfaces". It has several new sentences, a subset of which are shown here.
      • "An interface can be declared sealed when it is useful to restrict its subtypes to a fixed set of classes and interfaces."
      • "It is a compile-time error if an interface that does not extend a sealed interface is declared non-sealed."
    • There is a new Section 9.1.4 (the old Section 9.1.4 is proposed to be changed to Section 9.1.5) called "Permitted Subtypes" and here is a subset of sentences in this section.
      • "It is a compile-time error if a sealed interface has no permitted subtypes."
      • "It is a compile-time error if an interface declaration has an explicit permits clause but is not sealed."
      • "If a sealed interface I does not have an explicit permits clause, then it has an implicitly declared permits clause that lists as permitted subtypes all the classes and interfaces in the same compilation unit as I that declare I as their direct superinterface."

There are additional details of sealed types discussed in this draft JLS document that are not highlighted here. In particular, the proposed draft JLS changes specify handling of sealed classes, sealed interfaces, and permitted types within Java modules. In short, it's a compile-time error to have any class designated as permitted for a sealed class or sealed interface that is not in the same module as the sealed class or sealed interface.

The JEP for the sealed types preview feature and the proposed JLS changes for the sealed types preview are both currently in "candidate"/"draft" form, but it's encouraging to see progress being made in the area of sealed types. It will be interesting to see the forthcoming language specification changes related to binary compatibility.

3 comments:

Deepak Gangore said...

At the time of writing an interface or abstract class, how can one be sure that who/which class/interface is going to extend or implement is? Am i missing something here?

@DustinMarx said...

Hello Deepak,

That's a good question! I this the general approach we're already familiar with (and which you describe) will probably remain common in many cases. However, there will be cases with finite implementations that sealed types will bring new benefits. Perhaps the best documentation I've seen describing the motivation for sealed types is in the "Records and pattern matching" section of the "Data Classes and Sealed Types for Java" (February 2019) document. In that section, Brian Goetz provides an example of using switch on all cases of a given hierarchy such that no default is needed. Goetz then writes (I added the emphasis), "Both records and sealed types have a synergy with pattern matching; records admit easy decomposition into their components, and sealed types provide the compiler with exhaustiveness information so that a switch that covers all the subtypes need not provide a default clause."

@DustinMarx said...

Gavin Bierman's post "Exploring inference for sealed types" on the OpenJDK amber-spec-experts mailing list outlines "some tweaks to the sealed types design" with focus on "alternative design points, all supporting some sort of inference."