Sealed types

Brian Goetz brian.goetz at
Fri Nov 30 15:30:45 UTC 2018

>     |sealed interface Node { ... } |
>     In this streamlined form, |Node| may be extended only by its
>     nestmates. This may be suitable for many situations, but not for
>     all; in this case, the user may specify an explicit |permits| list:
>     |sealed interface Node permits FooNode, BarNode { ... } |
>     The two forms may not be combined; if there is a permits list, it
>     must list all the permitted subtypes. We can think of the simple
>     form as merely inferring the |permits| clause from information in
>     the same compilation unit.
> what inferring from the same compilation unit means ?

It means: if there is no "permits" list, the compiler is allowed to 
synthesize one that contains exactly the list of subtypes declared in 
the same compilation unit.  (Much like the way we synthesize the 
NestMembers attribute.)

> - it works for anonymous class declared in the same compilation unit ?

Anonymous classes are a good question.  On the one hand, I can imagine 
when they might be useful.  On the other, it means there's no way anyone 
-- including the current class, to which all the subtypes are accessible 
-- will be able to switch exhaustively over them.  I think we should 
consider banning them, as you can always fall back to a named class.  
The exhaustiveness part is important, and too easy to forget about when 
you're writing the class.

(Other restrictions: classes in the permits list must be in the same 
module (or if not in a module, same package and protection domain) as 
the sealed type, and must be accessible to the sealed type.)

> - it works for functional interface for lambda in the same compilation 
> unit ?

Same as for anon classes; if we ban one, we ban the other.

>   what exactly the permit list contains ??
>   (dynamic nestmate/sealed class to the rescue ?)

I don't seen an interaction with dynamic nestmates.  The permits list is 
an explicit list; if the dynamic class is not on the list, it can't be a 
subtype, even if its in the nest.  If we infer the list, we're not 
recording "all nestmates", but instead inferring it to be the list of 
nestmates known at compile time.

>   And in another compilation unit
>     Fun fun = x -> 2 * x;   // rejected because Fun is sealed ?


>     /Note:/ It might be allowable for VM support to follow in a later
>     version, rather than delaying the feature entirely.
> Does seems to be a good idea to divorce the two. It means you can 
> create classes with ASM that will work for a version of the VM but not 
> the next one.

I think you mean "does not seem to be a good idea"?   I agree, it's got 
problems, such as the ones you raise.  But it is a possible move we can 
make, so we can keep it on the board until we have more visibility into 
the cost of waiting for VM support.

>     *Accessibility.* Subtypes need not be as accessible as the sealed
>     parent. In this case, clients are not going to get the chance to
>     exhaustively switch over them; they’ll have to make these switches
>     exhaustive with a |default| clause or other total pattern. When
>     compiling a switch over such a sealed type, the compiler can
>     provide a useful error message (“I know this is a sealed type, but
>     I can’t provide full exhaustiveness checking here because you
>     can’t see all the subtypes, so you still need a default.”)
> Yes !
> I expect a public sealed interface with several package private 
> implementations to be a common pattern.

I agree qualitatively (and share your conclusion), but disagree with the 
quantitative statement here ("common").  I think it will be common _for 
platform and low-level library implementors_ to do this.  But if the 
feature is successful, this will probably be a tiny fraction of the 
sealed types in the world.  So yes, this is an important pattern, but I 
hope it is UNcommon.

> The implication is that you can not define (at least now) the 
> implementations inside the sealed interface because all class members 
> of an interface can only be public so you can not declare a 
> package-private implementation.  I don't know exactly why private 
> class are not allowed in interface, it seems to be an overlook for me.

Yes, this (and fields too, even though they kind of suck in interfaces), 
was largely overlooked.  We are gathering a list of "gratuitous nesting 
constraints", of which this is one, and at some point will bang them all 
out.  (Restrictions on static members in nested classes is another.  
Local interfaces and enums is another. Maybe even local methods.  Etc.)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the amber-spec-experts mailing list