Refinements for sealed types

Alex Buckley alex.buckley at
Tue Aug 20 21:56:26 UTC 2019

On 8/20/2019 12:40 PM, Brian Goetz wrote:
> Gathering the various threads in this discussion, here’s what seems a sensible landing place:
> 1.  A sealed _class_ with no permitted subtypes is a final class.  The distinction between declared-sealed-with-no-permits and declared-final is erased away.  [*]
> 2.  Sealed abstract classes and interfaces with no permitted subtypes are illegal.
> 3.  If a sealed type does not specify a permits list, it can be inferred by enumerating the subtypes in the same compilation unit.
> 4.  If a concrete class is a subtype of a sealed type declared in the same compilation unit, and none of the modifiers { sealed, non-sealed, final } are present, it is inferred to be sealed with an inferred permits list (which, according to (1), may be treated as final if there are none.) >
> 5.  (optional) It is an error to specify an explicit permits list if `sealed` is not specified.
> 6.  Otherwise, a subtype of a sealed type must have exactly one of the following modifiers: sealed, non-sealed, final.

I see two committed principles here:

1. Permitted subtypes are common; their enumeration isn't. It's almost 
like explicit `permits` is a separable feature that could be set aside 
for now.

2. Ceremony reduction is important enough to treat concrete direct 
subclasses of a sealed type specially.

However, that special treatment comes at the expense of another 
principle: "leaf nodes [implicitly final classes] are obvious". I was 
hoping to have this because implicitly final classes [sealed with zero 
permitted subtypes] are The Show. Below, it's kinda hard to figure out 
that class C is NOT a leaf node:
sealed interface I {}    // implicitly `permits C`

class C implements I {}  // implicitly `sealed` and `permits D`

... lots of other stuff ...
class D extends C {}     // implicitly `sealed` w/ no permitted subtypes

whereas below, the leaf nodes are mostly obvious by virtue of how the 
intermediate hierarchy is explicitly `sealed`:
sealed interface I {}            // implicitly `permits J`
sealed interface J extends I {}  // plainly not a leaf
sealed abstract class AC implements J {}  // plainly not a leaf

class PolarData extends AC {}      // maybe a leaf
class CartesianData extends AC {}  // maybe a leaf
// EOF, so yes, PolarData and CartesianData are indeed leaves

tl;dr We're back to having both sealed-ness and the 
potentially-non-trivial permits list be implicit, which was earlier 
thought to strain the reader. If we said that concrete direct subclasses 
of a sealed type were implicitly final, then ceremony reduction would 
still be high, and if you really don't want them to be leaf nodes then 
say `sealed` or `non-sealed`.


More information about the amber-spec-experts mailing list