> 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.

I am not sure I would raise these to the level of “principle”, as much as 
“expectation”.  In the typical co-declared sum type case, there may be many 
cases:

    sealed interface Letter {
        class A implements Letter { }
        class B implements Letter { }
        …
        class Z implements Letter { }
    }

Having to say “permits A, B, .. Z” here is both verbose (lots of cases) and 
seems pretty repetitive (the subtypes are RIGHT THERE.)  Same, to a lesser 
degree, with having to say “sealed” or “final” on each case.  

In the typical “restricted hierarchy” case, I expect there to be fewer subtypes 
(less fan-out), less co-declaration (will likely want to use top level 
classes), and simply fewer instances of this use (mostly, this will be used by 
platforms and libraries, rather than applications.)  So the ceremony here is 
(a) less substantial, (b) less frequent, and (c) more beneficial.  

So basically, this is special treatment for co-declared sums.  (We’re still 
more verbose than Haskell, even with these, sadly.)

> 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:
> 
> --I.java--
> 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`:
> 
> --I.java--
> 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`.

This seems reasonable too, because most concrete classes in such hierarchies 
_will be_ leaves.  In this world, though, it feels a little inconsistent to 
only do this when the subclass and the sealed type are in the same compilation 
unit; we could extend this to all concrete subclasses of sealed types 
(implicitly final, unless they say sealed or non-sealed).  This is consistent, 
but feels a little more action-at-a-distance-y.  So, its pick your poison.


Reply via email to