JDK-8242521 : compiler implementation for sealed classes
  • Type: CSR
  • Component: tools
  • Sub-Component: javac
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 15
  • Submitted: 2020-04-10
  • Updated: 2020-05-28
  • Resolved: 2020-05-28
Related Reports
CSR :  
Relates :  
Description
Summary
-------

Enhance the Java programming language with sealed classes. Sealed classes are
classes or interfaces that impose restrictions on which other classes or
interfaces may extend or implement them.

Problem
-------

Java's type system doesn't offer many options to control the degree to which a
class can be extended: Classes are either freely extensible (the default), or
they can be declared `final` in which case they can not be extended at all. This
disallows certain library designs, as well as limiting the analysis a compiler
can do in checking conversions and use-site exhaustiveness at compile-time. 

Solution
--------

The Java language will be enhanced by supporting sealed classes, which restricts
which classes may be a subclass of a sealed class. This allows various new kinds
of library design; for example, to include a class and all of its subclasses.
They also potentially enable exhaustiveness analysis at the use-site, such as
when switching over type patterns for an instance of a sealed class. These
features will constitute a preview feature 
([JEP 12](http://openjdk.java.net/jeps/12)) in Java SE 15.

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

See attachments for JLS updates; tree API update below. 


com/sun/source:

    diff -r 9672de6ee0d7 src/jdk.compiler/share/classes/com/sun/source/tree/ClassTree.java
    --- a/src/jdk.compiler/share/classes/com/sun/source/tree/ClassTree.java	Tue Apr 07 09:50:36 2020 -0700
    +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/ClassTree.java	Fri Apr 10 13:08:16 2020 -0400
    @@ -86,6 +87,28 @@
         List<? extends Tree> getImplementsClause();
     
         /**
    +     * {@preview Associated with sealed classes, a preview feature of the Java language.
    +     *
    +     *           This method is associated with <i>sealed classes</i>, a preview
    +     *           feature of the Java language. Preview features
    +     *           may be removed in a future release, or upgraded to permanent
    +     *           features of the Java language.}
    +     *
    +     * Returns the subclasses permitted by this type declaration.
    +     *
    +     * @implSpec this implementation returns an empty list
    +     *
    +     * @return the subclasses
    +     *
    +     * @since 15
    +     */
    +    @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
    +                                             essentialAPI=false)
    +    default List<? extends Tree> getPermitsClause() {
    +        return Collections.emptyList();
    +    }
    +
    +    /**
          * Returns the members declared in this type declaration.
          * @return the members
          */

Additional links
-------

* javadoc: http://cr.openjdk.java.net/~vromero/sealed_CSRs/jdk.compiler/javadoc.00/module-summary.html
* specdiff: http://cr.openjdk.java.net/~vromero/sealed_CSRs/jdk.compiler/specdiff.00/overview-summary.html
Comments
Moving updated request back to Approved.
28-05-2020

Four further small changes to the spec: 1. 8.1.6/9.1.4: Explicitly state that if sealed class or interface is in a named module then subclass/subinterface must be in the same named module 2. 9.6: Forbid sealed annotation type declaration 3. 13.4.2.1: Exception thrown should be IncompatibleClassChangeError to match the JVMS 4. 13.5: Missing cases for sealed interfaces
26-05-2020

[~darcy] thanks!
13-05-2020

Thanks [~gbierman]; moving updated request to Approved.
13-05-2020

Thanks Joe: I have attached a revised spec (jep360-20200513.zip). It now matches the behaviour of the compiler: An enum class is either implicitly final or implicitly sealed. In the later case the enum constants with class bodies implicitly declare final classes. The changes are listed in the header.
13-05-2020

Thanks [~gbierman]; FWIW the intention would have been clearer to me if wording like "explicitly or implicitly final" was used given the paragraph discussing how emum classes are implicitly final (unless there are specialized enum constant, etc.).
11-05-2020

Thanks Joe. No, we want to support enums implementing a sealed interface. In fact, we used to call out enums (and records with an appropriate JEP pointer) explicitly as a special case in this rule. However, it got simplified as enums are considered *implicitly* declared final in the JLS. That said, you have pointed out a small corner case where this doesn't work, i.e. where an enum constant has a class body. So I think we need to add this back into the spec. I checked the compiler, and (i) it supports enums implementing sealed interfaces, and (ii) it deals properly with this corner case. So this is just a small spec bug. I'll update the spec accordingly.
11-05-2020

Perhaps a spec statement like "any enums that are not implicitly final are implicitly sealed" would give the desired results (enum classes being able to implement sealed interfaces).
11-05-2020

Moving to Provisional. A question about the interaction of sealed interfaces and enums. An enum can implement an interface. in the revised 8.1.1.2 it states: It is a compile-time error if a class has a sealed direct superclass or a sealed direct superinterface and is not declared final, sealed, or non-sealed. And enums are in effect final, even though they cannot be declared as explicitly final in the source. (And there is a wrinkle if the enum has specialized enum constants.) Is it the intention that enums *cannot* implement a sealed interface? Also, in terms of the javax.lang.model API, it would be preferable if "non-sealed" was recognized as a keyword under --source 15 and enable preview being true.
09-05-2020

I have uploaded the latest spec at: jep360-20200506.zip
06-05-2020