Sealed/Nestmates in java.time.*

Brian Goetz brian.goetz at oracle.com
Tue Jun 11 14:13:27 UTC 2019


A good question, not only because of the specific issues in java.time, 
but because this issue will likely come up in other corelibs situations 
too.

First, some clarification on the terminology.  _Nests_ are a new (JVM) 
term for describing a concept the language has had all along -- that a 
certain set of classes were co-declared with the intent of sharing an 
access control context.  Nested/inner classes in the Java language have 
always had this characteristic, but the compiler had to do some 
contortions to fit it into the each-class-is-its-own-world access 
control model of the JVM. Nests allow language compilers to declare that 
multiple classes share an access control context, and Java uses this for 
nested/inner classes (but other languages could it use it differently.)  
But, nests are not really a user-accessible feature.  (There is some 
allowance for nestmates to be _dynamically_ added through class loading; 
VM anonymous (VMAC) classes are morally the same sort of thing, and we 
use them (for example) in lambdas to "inject" classes into the access 
control context of a running class.  Again, more a tool for compilers 
than for users.)

_Sealed classes_, on the other hand, are a language feature, and fair 
game for use in libraries.  Historically, there were some "tricks" for 
obtaining the effect of sealing (e.g., package-private constructor or 
abstract method) which would prevent subclassing outside of the current 
package, but this only works for classes, not interfaces.  (Similarly, a 
class or interface in a non-exported package is effectively sealed, but 
in an accidental way.)

For a class that has used one of the tricks to obtain the effect of 
sealing, making it effectively impossible for third-party code to extend 
the class, promoting to a sealed type is a fine move (and makes it more 
clear what is going on.)  For a class that has _not_ employed such 
tricks, making a class sealed will have compatibility consequences, and 
so must be considered more carefully.  (The classes in 
java.lang.constant anticipate sealing, and their spec says "don't extend 
me, you won't like it"; this is also a valid way to manage the 
compatibility issues.)  Similarly, a class that is final can be made 
sealed (either explicitly, or implicitly by sealing a supertype) without 
compatibility issue.

For these specific classes, since they are not part of the same 
compilation unit, you'd want to declare it with the full syntax:

     public sealed abstract class ZoneId
         permits ZoneOffset, ZoneRegion { ... }

This is a compatible change and captures the design intent, so it seems 
a reasonable move.

On 6/11/2019 9:16 AM, Stephen Colebourne wrote:
> Not sure if this should go to core-libs now. Anyway, I realised today
> that three classes in java.time.* probably form a nest and would be a
> reaonable test for any new nest/sealed syntax:
>
> * ZoneId
> * ZoneOffet
> * ZoneRegion
>
> The context was this issue: https://bugs.openjdk.java.net/browse/JDK-8225566
>
> I see these as a nest because the intention is that they form a closed
> set with no additional subclasses. (Given that ZoneRegion is
> package-private, the exhaustivenss check of sealed types won't be
> useful, but it still seems worth documenting in code the closed set)
>
> Stephen



More information about the amber-dev mailing list