Superclasses for inline classes

Brian Goetz brian.goetz at oracle.com
Thu Feb 6 17:53:25 UTC 2020


I've been thinking about this, and gone around in circles a few times.  
The properties laid out here are understandable and easily checkable at 
both compile and run time.  (I might add "no synchronization", or at 
least "no synchronized methods".)

I agree that having some sort of class-level modifier gives this concept 
too much importance.  And normally, I would take the position that a 
property like this would have to appear in the declaration somewhere, to 
capture the fact that conformance to these properties is not merely 
accidental and subject to change tomorrow.  But, lately I've been 
questioning this.

Reasons to have some sort of indicator of "I am an initialization-free 
class":

  - Allows author to capture design intent
  - Allows compiler to type-check conformance to requirements, based on 
design intent
  - Propagates design intent into documentation, where subclasses can 
see that this is safe to extend

But it occurs to me that all of these are within the bounds of what 
_annotations_ are allowed to do; we did the same with 
`@FunctionalInterface` that, while not required, turns on additional 
compile-time type checking and documentation.

I am currently thinking that we can adopt Dan's rules at the language 
level, and have an annotation @InitializationFree, which: (a) declares 
intent to conform to the contract of initialization-freedom, (b) 
unleashes compile-time type checking for same, and (c) causes a blurb to 
be emitted into the Javadoc along the lines of "This is an 
initialization-free class" -- but that the language specification works 
entirely in terms of structural properties.  We can say that "inline 
classes may extend initialization-free inline classes", and be done.


Regardless of compile-time type checking, we will likely want to do the 
analysis and write the result into the classfile (e.g., an 
InitializationFree class attribute), which can be seen as a 
necessary-but-not-sufficient signal for the VM to allow the class to be 
used as a super for an inline class.  When we go to load a class with 
this attribute, we can verify that it actually conforms:

  - Fields: no fields
  - Constructors/initializers: no ctor/initializer
  - Class declaration: it is abstract, and its super is i-free
  - Synchronization: No methods have ACC_SYCHRONIZED

When we go to load an inline class, we check the i-free bit on the 
superclass.

None of these checks seem all that burdensome to the VM.

It does mean that dusty abstract classes need to be recompiled before 
they can be bases for inline classes, which, on balance, seems OK.

> Language model
>
> An inline class may extend another class, as long as the superclass has the following properties:
> - It has no instance fields
> - It has no constructors
> - It has no instance initializers
> - It is abstract* or Object
> - It extends another class with these properties
>
> Subtype polymorphism works the same for superclasses as it does for superinterfaces.
>
> (*Remi points out that we could drop the 'abstract' restriction, 
> meaning there may be identity instances of the superclass. Given the 
> restriction on fields, though, I'm struggling to envision a use case; 
> the consensus is that 'new Object()' is probably something we want to 
> *stop*  supporting.)
>
> Call a class that satisfies these constraints an "initialization-free class" (bikeshedding on this term is welcome!). Like an interface, its value set may include references to both inline class instances and identity class instances.
>
> We*do *not*  want the initialization-free property to be expressed as a class modifier—this feature is too obscure to deserve that much prominence, encouraging every class author to consider one more degree of freedom; and we don't want every class to have to manually opt in.
>
> But we*do*  need the initialization-free property to be part of the public information about the class. For example, the javadoc should say something like "this is an initialization-free class". Otherwise, it's impossible to tell the difference between, e.g., a class with no fields and a class with private fields.
>
> In the past, a Java class declaration that lacks a constructor always got a default constructor. In this model, however, an initialization-free class has no constructor at all. A 'super()' call directed at such a class is a no-op.



More information about the valhalla-spec-observers mailing list