Sealed types -- updated proposal

Brian Goetz brian.goetz at
Thu Jan 31 19:12:50 UTC 2019

Since this seems to be the open issue that has the most divergence….

The basic problem is that the user is “forced” to choose between a convenient and readable way to declare the classes (a group of related, short declarations in one place), and exporting a flat namespace.  And the downside of a non-flat namespace is that then the client has to say Node.AddNode instead of just AddNode, which is inconvenient.  So we can have what’s nice for the declaration site, or what’s nice for the use site, but not both.  Here are the options that have been proposed so far: 

Option 1: Do nothing; just tell clients to `import static Node.*`.  

Option 2: Automagically import-static the nested subtypes of Node when you import sealed type Node.  

Option 3: Do what we do for enums: when switching on an enum of type C, allow `case` labels to omit the `C.` prefix.  

Option 4: Relax the rules about public auxiliary types. 

#1 is a viable solution, and has the benefit that it requires no incremental complexity.  IDEs will help here too.  So doing nothing is an acceptable choice; this should be our null hypothesis.  

#2 is cute, but (a) import processing is already nastier than it looks, and (b) this feels odoriferously specific to the interaction between two features.  

#3 Seems pretty justifiable to me; enums and sealed types are sibling constructs (both are about controlling the number of things that can be a member of the value set), so having a similar rule for both is arguably reducing gratuitous asymmetries.  It is also a smaller change than #2 or #4, and likely will cover a great deal of the pain-causing situations.  

People who maintain large codebases (JDK, Google) are pretty down on #4; we ban auxiliary classes in the JDK in part because it makes tooling support so much harder.  Google does something similar.  This one strikes me as something that seems enticing at first but ultimately would cause other problems.  It also shares downside (b) from #2.  

Given that, I’m going to cross #2 and #4 off the list for consideration, and restrict the choices to #1 and #3 (open to new ideas that have not yet been discussed.)  I have a preference for #3, but could be moved off it.  

> On Jan 9, 2019, at 1:44 PM, Brian Goetz <brian.goetz at> wrote:
> Auxilliary subtypes. With the advent of records, which allow us to define classes in a single line, the “one class per file” rule starts to seem both a little silly, and constrain the user’s ability to put related definitions together (which may be more readable) while exporting a flat namespace in the public API. 
> One way to do get there would be to relax the “no public auxilliary classes” rule to permit for sealed classes, say: allowing public auxilliary subtypes of the primary type, if the primary type is public and sealed. 
> Another would be to borrow a trick from enums; for a sealed type with nested subtypes, when you import the sealed type, you implicitly import the nested subtypes too. That way you could declare:
> semi-final interface Node { 
>     class A implements Node { }
>     class B implements Node { }
> }
> ​but clients could import Node and then refer to A and B directly:
> switch (node) { 
>     case A(): ...
>     case B(): ...
> }
> We do something similar for enum constants today.

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

More information about the amber-spec-experts mailing list