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