Local classes & sealed classes

Brian Goetz brian.goetz at oracle.com
Fri May 1 21:17:00 UTC 2020


Erring on the side of quick answers because time is getting tight.

> 1) A local class can extend a sealed class that lacks a 'permits' clause.
>
> The implicit list of permitted subclasses will include all classes declared in the same compilation unit.
>
> sealed class A {
>      void m() {
>          final class B extends A {}
>      }
> }
>
> Note that the local class can't be declared 'sealed' or 'non-sealed'—see below—but can be declared 'final'.
>
> There's nothing particularly wrong with this, other than the fact that it's impossible to rewrite it with an explicit 'permits' clause.
>
> I can see it being a useful way to handle, say, an interface that declares a handful of factory methods to produce a limited set of implementations.

We already prohibit lambdas and anonymous classes from extending sealed 
classes at all, inferred or not.  We didn't explicitly consider local 
classes (oops), but I wouldn't like this behavior. If you can't write 
down the permits clause, you shouldn't infer it. I think we should 
exclude local classes from candidacy.

> 2) A local class cannot be 'sealed' with an implicit 'permits' clause.
>
> Because local classes aren't recursive (their scope only goes from their declaration onward), two peers can't refer to each via 'permits' and 'extends'. But an implicit 'permits' gets around that problem:
>
> void m() {
>      sealed class A {}
>      final class B extends A {}
> }
>
> Again, I can see not wanting to support this because it's impossible to rewrite it with an explicit 'permits' clause.
>
> On the other hand, it's pretty useful—throw in local interfaces and local records, and it's not hard to imagine a small sealed hierarchy sprouting up.
>
> On the other other hand, the local-ness of the class already "seals" it to the declaring method, so there's not a lot to be gained by explicitly saying 'sealed', especially when you can't enumerate your permitted subclasses. The effects would be:
> - Forcing all subclasses to be explicit about sealed/non-sealed/final
> - Preventing extension by anonymous classes or lambdas
> - Limiting what subclassing can be done at runtime via, e.g., bytecode spinning
> - Anything else?
>
> On the other^3 hand, Brian's crusade for uniform nesting will cjamge some of these assumptions, and programmers will want to play with sealed classes in a top-level main method.

The main thing you lose here is you don't get the nice exhaustiveness 
checking for switches.

All that said, I'm in favor of "prohibit" on all of these.  What is 
sealing for?  1. a tool for building APIs that you will expose but want 
to control, and 2., for building algebraic data types that can take 
advantage of exhaustiveness checking in switch.  THe first doesn't apply 
to local classes, and the second is a nice-to-have, but "prohibit and 
revisit when we get to uniform nesting" seems the prudent move here.


More information about the amber-spec-observers mailing list