On Apr 24, 2023, at 4:18 PM, Dan Heidinga <[email protected]> wrote:

My misgivings around the term "default" are due to having already used it to 
describe interface methods with a default implementation.  The term has also 
been used related to the default (initial) value of variables but that has no 
syntax associated with it.  So precedent supports its use..... a mixed result I 
guess?  ....And I just found a section in the JLS (8.8.9) that already defines 
the default constructor for a class.  That's even stronger precedent for 
reusing the term here given this is a slightly different kind of default 
constructor.

Forwarding some notes I put together about other uses of "default constructor". 
This exploration dampened my enthusiasm for trying to unify these different 
concepts—too many differences, IMHO. I think we're better off with a different 
keyword (currently trying out "implicit" in the JEP text, but still open for 
more bikeshedding).

-----

Here are some different "default constructor" concepts that need to coexist in 
the language, with a list of their properties.

special value class constructor:
- must be explicit
- must be public (maybe can relax this, but I don't want access checks in 
Arrays.newInstance)
- distinct from an explicit constructor with an empty body (and maybe we allow 
overloading of both?)
- no execution, can't throw; ignores field/instance initializers
- not subject to final field initialization rule
- gives the class a default instance (*preempting* field initializers!)
- possibly able to opt in to non-atomic instance creation as well
- implies can't have field circularity and can't be an inner class
- TBD how encoded in class files/reflection, there's some sort of special 
metadata

identity class default constructor:
- implicit, or can be explicitly stated (e.g. for documentation) with an empty 
body or a 'super()' body
- doesn't get implicitly provided if any other constructor is declared
- compatibility constraint: lots of explicitly stated default constructors in 
the wild
- has same/greater access than the class
- includes super() call and field/instance initializers, may throw
- no relationship to default instances or non-atomic instance creation
- error if the class has uninitialized final fields
- indistinguishable from any other no-arg constructor by class files/reflection

abstract class "trivial" constructor (if absent, the class is implicitly 
'identity'):
- implicit, or can be explicitly stated (e.g. for documentation) with an empty 
body or a 'super()' body
- doesn't get implicitly provided if any other constructor is declared
- compatibility constraint: lots of explicitly stated "trivial" constructors in 
the wild
- has same/greater access than the class
- no relationship to default instances or non-atomic instance creation

record class canonical constructor:
I won't dig into it, but this has its own special behavior

(As an aside, there's also "default method", which uses the keyword 'default', 
and means something totally different.)

So, concretely, could we re-use the special value class constructor syntax in 
identity classes as a new way to explicitly express the default value 
constructor? There would be many mismatches:
- it shouldn't give the class a default instance
- it should do super() and run field/instance initializers
- it doesn't imply any field circularity or inner class restriction
- it would (somewhat surprisingly) allow final fields without explicit 
initialization
- if it's detectable via reflection, we're retroactively saying all legacy 
classes need to be recompiled to get that capability, and all legacy attempts 
at explicit default constructors have to be rewritten

Abstract classes still need to recognize legacy attempts at explicit "trivial" 
constructors. And record classes really want canonical constructors as a 
distinct concept from allowing a default instance.

My conclusion is I don't think this is a good opportunity for unification. I 
get the interest in doing so—it is a bit much to have all of these similar 
concepts floating around, with subtle rules in each case—but I think the need 
for an explicit opt-in syntax in value classes conflicts with the longstanding 
"convenience feature" treatment we've used elsewhere, and also the different 
semantics around code execution are hard to reconcile.

Reply via email to