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.go...@oracle.com> 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.
> 

Reply via email to