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 <[email protected]> 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
