Unnamed classes (was: Paving the on-ramp)

John Rose john.r.rose at oracle.com
Wed Oct 19 22:59:34 UTC 2022

On 19 Oct 2022, at 13:35, Brian Goetz wrote:

> Let's pull on this string.
> When we say `javac Foo.java`, the compiler has to create a class file, 
> and doesn't have the benefit of a declared class name. The logical 
> output file is `Foo.class`, because otherwise the next thing the user 
> is likely to do is `java Foo`, and the class loader is going to look 
> for Foo.class.

I guess what I’m suggesting here is that what’s new (or what 
*should* be new) is a full removal of all coupling between the file name 
(of the .class file) and the class’s bytecode name (in the ClassFile 
structure).  VM anonymous classes (VMACs) are the precedent I’m 
looking at; IIRC only the package prefix of a VMAC is significant to any 
VM operation.  (With minor exceptions:  Reflection and stack traces 
probably report a string that depends on the bytecode name.)

It seems reasonable to steer towards such a decoupling, because it would 
be (a) similar to what we have with VMACs, but with an accidental 
inclusion of a file system container *of an irrelevant name*; it would 
also be (b) useful to put zero constraints on the classfile name (other 
than a .class suffix perhaps) so that tools have fewer irrelevant 
details to worry about.

> A .class file has a ClassFile structure, which has a `this_class` 
> field which names the current class.

Names it for what purposes?  For a nameless class, the only purposes are 
informative as with VMACs.  I think that not even `Class.forName` should 
be able to recover the current class, only `this.getClass()`.  Maybe 
that’s too much of a reach?

> We experimented with calling the class something like `$Foo` or 
> $Unnamed, but this trick just garners a NoClassDefFoundError, with 
> reason "wrong name".  This error comes from the native method 
> `ClassLoader::defineClass1`.

That’s a superficial problem.  We are defining a new path for loading 
classes, so we have a right to adjust the rules.

OTOH, and alternatively, and more in line with the gradual on-ramp:  We 
could insist that, no, we are just defining an easier way to define a 
regular old class; we take care of issuing the name for you.  Which is 
less surprising, that a named class you didn’t declare pops up 
somewhere and with a name vaguely like the filename, but is “just a 
class you could have coded”, or that, if there is no name, none of the 
name-related operations work.

I guess part of the issue is the anonymous classes (of various sorts) 
are two things at once:  1. a really obscure power-user feature, and 2. 
a desirable default early on the onramp.  Having it both ways causes 

If we embrace “it is anonymous” I think we get the cleanest 
experience.  People won’t be tempted to predict the name and refer to 
it somehow (with reflection or even source code).

If we embrace “it has a name you didn’t pick” I think we get a 
simpler onramp story, but at the cost of dark corners in the UE.  Users 
will immediately try to exploit the fact that the name is 
semi-predictable, and write code that works with the names of these 

> With inner classes, we've taken the position that class names with $ 
> in their name are likely to be unstable names not to be counted on.  
> So calling it $Foo sends that signal, good.  But we'd have to be 
> willing to loosen the checking in the class loader to allow loading a 
> class with a slightly mangled name such as $Unnamed (and then make the 
> launcher more tolerant of that.)

In the end, I’m totally willing to do this.

Idea:  Have the launcher not call defineClass at all, but rather take 
the byte image of the *.class file, and run it into the VM as a VMAC.  
That is a principled position that will prevent lots of nonsense about 
secret names.

— John
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20221019/e1d98526/attachment-0001.htm>

More information about the amber-spec-experts mailing list