JDK-8300786 - No longer require super() and this() to appear first in a constructor

Tagir Valeev amaembo at gmail.com
Tue Jan 31 21:29:33 UTC 2023


Hello!

>From an IDE guy point of view, I can say that #1 already greatly
reduces our pain in automated refactorings and quick-fixes. Often, we
need to insert additional statements before the refactored expression.
Notable refactorings include "inline method call", "introduce local
variable", "convert stream to loop". All of them are disabled in
certain contexts like inside this/super invocation, as we cannot add
statements before. It's even more pitiful, as sometimes refactoring is
performed internally in several steps, and subsequent steps remove
extra statements. E.g., "inline method" may add temporary variables
for parameters or return values, and then optimize them away yielding
a single expression as a result. So it would work inside this/super
expression even in current Java, but due to internal architecture, we
don't know in advance whether we'll need additional statements, so we
refuse to refactor completely if the call is inside this/super. Things
will be much simpler if additional statements were allowed.

#2 would unlock some more refactorings, notably "Convert ?: to
if-else", if ?: operator appears in this/super invocation. But in
general, it adds much less benefit.

I don't think that #3 over #2 adds anything useful for IDE functionality.

#4 might allow to quick-fix compilation error (surround with
try-catch) when a checked exception is thrown from this/super call
arguments. Currently, we suggest such a fix but it produces another
compilation error. In any case, this is probably a rare situation when
you have such a case and really want to handle this exception right in
the constructor, rather than rethrowing.

To conclude, I would be quite happy with #1 already.

With best regards,
Tagir Valeev.

On Tue, Jan 31, 2023 at 9:46 PM Archie Cobbs <archie.cobbs at gmail.com> wrote:
>
> Hi folks,
>
> I'm working on this issue:
>
> JDK-8194743 - Permit additional statements before this/super in constructors.
>
> Obviously this change requires a JEP, and so we have this JEP draft for review:
>
> JDK-8300786 - No longer require super() and this() to appear first in a constructor
>
> Here's a summary of the discussion that's occurred so far on amber-dev...
>
> People are agreeable with the general idea of relaxing the JLS rules here, but of course the devil is in the details.
>
> The current JMVS gives constructors a lot more flexibility wrt. superclass initialization than the JLS:
>
> Multiple invocations of this() and/or super() may appear in a constructor, as long as on any code path there is exactly one invocation
> Arbitrary code may appear before this()/super(), as long as that code doesn't reference the instance under construction, with an exception carved out for field assignments
> However, invocations of this()/super() may not appear within a try { } block (i.e., within a bytecode exception range)
>
> So the question becomes, how far to push the JLS up against these limits, or conceivably even past them (i.e., relaxing both the JLS and JVMS).
>
> Roughly in order of increasing aggressiveness, here are some of the options that have been discussed (these are not all mutually exclusive):
>
> Permit "static context" code prior to super()/this(), but otherwise super()/this() still must occur exactly once and as a top-level statement in the constructor.
> Allow arbitrary appearances of super()/this() in constructors, and apply DA/DU analysis like a blank final field to verify exactly one ever gets invoked
> Also allow assignments to fields declared in the same class prior to super()/this()
> (JVMS mod required) Allow super()/this() within try { } blocks, as long as within any catch block execution completes abruptly with another throw
>
> #1 is the minimal change. It accomplishes the basic goal of allowing "housekeeping" prior to superclass initialization. It also requires fairly minimal JLS changes (drafted already in the JEP).
>
> #2 is arguably a more natural way to relax things, but beyond #1 it addresses a fairly niche set of incremental use cases, and would have a large impact on the JLS for that relatively meager marginal return.
>
> #3 is debatable. The 'this' escape problem (e.g., HashSet(Collection)) is very real and Java provides victim subclasses with no easy way to avoid it. This feature would make it easy to avoid. However, it has a conceptual cost. Allowing field assignments, but no other 'this' references, is an obvious hack/exception to the rules. To be sure, there are practical reasons for it (which is why it was added to the JVMS in the first place), but from a language design point of view it left some people a little uneasy. It's a classic beauty vs. function debate.
>
> #4 is kind of a related side issue that came up. It could stand alone as an independent change. I'd be curious to hear people's opinions here. It would allow you to catch exceptions thrown by a super()/this() call as long as you then (re)throw some exception. It would also fix a difficulty for bytecode weaving tools that do things like measure method execution times.
>
> One could also argue that by making super()/this() calls more like normal method calls (less "special"), items #2 and #4 would improve language harmony, etc.
>
> In any case, the current JEP draft takes the conservative route and opts for #1 only.
>
> Thanks,
> -Archie
>
> --
> Archie L. Cobbs


More information about the amber-spec-experts mailing list