Different handing of "this" vs. "MyClass.this" in definite assignment

John Rose john.r.rose at oracle.com
Fri Dec 2 19:30:05 UTC 2022


I was there when these rules were written, so I added a comment to the bug explaining what’s up here.

https://bugs.openjdk.org/browse/JDK-8193904?focusedCommentId=14542315&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-14542315

In short, we have no good changes on the table here.  The JLS is the way it is at this point intentionally for good reasons, summarized in the above comment.

Since changing the JLS is super-expensive, even a neutral change would need to be highly beneficial to the whole ecosystem.  Removing perceived inconsistencies (that have been unchanged for 25 years) is not highly beneficial to the whole ecosystem.

I think Archie got at the heart of the problem in this comment here:

> Presumably the reason for the different treatment is because in general the qualifying expression could be arbitrarily complex and the compiler can't be expected to detect any possible qualification in front of "foo", so why even start down that road?

Exactly.  Don’t start down that road, unless (1) you know where it goes, and (2) that it gets somewhere good, and (3) you can get there before you run out of gas.  Don’t start just because you like the first billboard you see, or on a road which takes you to a tarpit, or with only enough supplies to travel on the first day of a week-long trip.  I think we might have all three problems here.

Regarding (2), better uninitialized variable control is I think the proper goal here, not some consistency of all the things.  Dynamic checks are required to get the next level of value, IMO. Please see my comment on the bug for more details.

Regarding the PR:  It intentionally changes javac to deviate from the JLS.  That’s a non-starter.  (It got my attention but that’s a limited resource!)  Before we change javac to make it compile a language we like better, we first have to decide to change the JLS.  The JLS is not the Java Language Suggestions; it is the foundation of our whole ecosystem, and every word in it counts.  Breaking those words breaks promises of compatibility we have made to literally millions of programmers over decades.

Regarding tweaks to the Java language:  It might be interesting to look up the history of Project Coin, where we explicitly solicited, discussed, and implemented small improvements to the JLS and (only then) the Java toolchain.  Amber and Valhalla are the latest venues that we have created for making JLS changes, and this time around the changes tend to be larger in scale (than in Coin).  But we constantly keep in mind the possibility of applying Amber or Valhalla feature work more widely or “consistently” (for a reasonable sense of “consistent”).  By the way, Brian is the final authority on such work today, and the present note is my interpretation of how JLS evolution is working under his leadership.

Here’s a current (not decades old) example of how static analysis in the JLS is evolving and how the rules are adjusted.  The JLS have always constrained use of “this” in a constructor; you have to call “super” first, but then you have your own uninitialized fields you are responsible.  (And the “super” could have called one of your own overrides, which lets the super access the uninitialized value of one of your fields.  Turing machines are wily beasts.)

Now, Valhalla and Amber are adjusting the rules for initializing fields in constructors, so that they are different for classic Java classes, and for Valhalla value classes, and for Amber records.  With Valhalla value classes in the current prototype, there is not “super” call, but you cannot touch “this” until every field of “this” is definitely assigned.  We could have done that from the beginning for all classes, but it would have been a hard restriction to live with.  Imagine the objections:  “You mean I can’t call my logging helper function at the top of my constructor?”

Still, though the designs are well-reasoned, the differences bug me a little.  Since the differences apply to emerging parts of the language, we might consider spreading around the rules for value classes so they benefit other kinds of code.  What I’m thinking of (Brian you know this already) is perhaps we could take some error conditions for premature use of “this” in value classes and turn them into warnings for classic classes, so that code that circumvents the DU/DA rules, to obtain access to blank final fields uninitialized, will suddenly sprout lint warnings.  (Or even turn the Valhalla errors into warnings, if we decide consistency wins at that point; it doesn’t always win, not by a long shot.)  The extra warnings might be tolerable to the ecosystem, and it would be useful for some users (not all) to chase down the warnings and either fix code or suppress the warnings explicitly.

But, for this idea, as for any other, would the benefits to the ecosystem be worth the development cost?  A sharper question is, should we pause some other language feature before we enact some cleanups or generalizations that appeal to us?  We can’t do everything at once, and just having a clever idea (like better warnings on incomplete “this”) or a clever fix to javac code (like Archie’s) doesn’t help us decide what our priorities are.

(And static checks only get us a subset of safety.  I hope someday to add dynamic checks for uninitialized variables to the mix, to catch more user errors sooner.)

If I’ve missed some other goal for this PR besides adjusting DA/DU rules and/or increasing “consistency”, I apologize for missing it; it wasn’t clear to me.  But the above is where my mind goes when the question arises “what about the rules for this.x?”

— John


More information about the amber-dev mailing list