<init> vs. <make> vs. $make, named [de/re]constructors
john.r.rose at oracle.com
Sat Mar 10 21:16:21 UTC 2018
On Mar 10, 2018, at 1:01 PM, John Rose <john.r.rose at oracle.com> wrote:
> (I'm going to send a separate note about this.)
We discussed one future option to make the JVM specially aware of
<make> the way it is aware of <init>, and then restrict the new/dup/<init>
dance to *only* occur inside of <make> in the same nest.
If this is the only reason to coin a new magic name <make>, it might
not be enough motivation. But there might be other reasons.
Another reason for a magic name is to unambiguously link the source
construct DoubleComplex(a,b) to a factory method. The JVM does
*not* replicate the class base-name as the factory name, and I'd like
to avoid that in the future too; I think it's just an artifact of Java's C++
heritage, and nothing to do with VM-level requirements. Hence
<init> is the VM-level name where the type name occurs in the
source code. So for factories we also need a canonical name for
a value class's "principal factory". It could be $make or <make>
or some other bikeshed color. I slightly prefer <make> because
I think we *will* want to hook some structural constraints on it,
and that's easier to swallow of the name is *really* magic, rather
than "look he's got a dollar sign on him!".
Another way is to allow the translation strategy and/or user to
choose the factory name, and for the JVM to define an
ACC_FACTORY bit to do the jobs that <make> would do.
We'd still want, IMO, to fold DoubleComplex down to something
like $make, but with the ACC_FACTORY bit.
Either ACC_FACTORY or <make> scales out to other uses
besides value type factories. It allows named factories on any
kind of type. If we do a translation rule, for values, where
DoubleComplex(a,b) is a call to DoubleComplex.$make(a,b),
we can also take a later option to have List(a,b) be a call to
List.of(a,b), where the ACC_FACTORY bit on List.of gates
the decision. Or we would add List.<make> which calls
List.of, for the same effect.
(I happen to find List(a,b) attractive, though surely opinions
will vary widely. Doubtless some people find "new" reassuring,
and it was very reassuring in the long ago days when
folks didn't trust GC technology and wanted to keep a
sharp eye on allocation sites. But the days are long
gone of "new" being part of a crisp, simple performance
A decision to use $make/ACC_FACTORY instead of <make>
allows named factories too: DoubleComplex.imag(x), etc.
That seems to be a vote in favor of $make not <make>,
or perhaps an argument to have both, one for structural
constraints and one for naming of principal factories.
We are discovering as part of the Amber project that
constructors often occur paired with deconstructors.
Principal constructors (or for values factories) are paired with
principal deconstructors, which unpack an object in exactly
the reverse order in which it was packed by its principal
constructor. Name factories want to be paired, also, with
named deconstructors. (Anti-factories? Co-factories?
This leads to the possibility that, if a factory has structural
constraints, then maybe a deconstructor has coordinated
constraints. I'm just speculating here; I don't see a concrete
example yet, except perhaps the treatment of final fields.
This leads me to the following tentative results, which seem
"OK for today" but could change:
- The new/dup/<init> dance could be constrained to nests,
but there's no tighter constraint (like factories only) that
- No need seen, yet, for ACC_FACTORY.
- Java translation strategies need a tactic for naming principal
factories. And for naming deconstructors paired with constructors
or factories. There isn't a firm need for the JVM to help with
this but doing so would be unsurprising, given <init>.
There is a similar line of consideration for handling the initialization
*and reinitialization* of final fields, in reconstructors *and reconstructors*.
Marking reconstructors (like withers) *might* require an ACC_*
bit to relieve structural constraints that relate to final fields, and
currently allow enhanced access inside of <init> but only there.
Named [re]constructors might need similar access, leading to
either an ACC_CONSTRUCTOR bit or else a relaxation of
some <init> capabilities to the whole nest.
So another "OK for today" conclusion might be:
- Consider marking some methods as ACC_RECONSTRUCTOR
and allowing final updates in those methods. Use this marker on
reconstructors, in place of some extension of the <init> code shapes,
which are already overburdened.
- Or, consider relaxing rules for update of final fields to the whole nest.
(I know we just fixed a security bug in that space, but still look at it.)
More information about the valhalla-spec-observers