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.

Reply via email to