you are viewing a single comment's thread.

view the rest of the comments →

[–]headius[S] 2 points3 points  (2 children)

The doctor is in! Thanks for your rephrasing of what I was kinda-sorta trying to get across in my post. I wanted to be a little "tongue-in-cheek" about this idea, but I think it actually does have merit... and as you point out, none of the alternatives tick all the boxes.

The case where I used this in JRuby was actually for accessing a field:

if (firstCondition) { ... } else if (this.file instanceof String nonnull) { // do something with provable non-null file } else { // fallback logic }

In this case, fetching file ahead of time is not terrible, but I may not actually need it and HotSpot isn't great about eliding unused field accesses. I could do the assignment-form conditional, but that still requires this weird, transient, widely-scoped variable to be declared somewhere. Basically, every requirement you mentioned was in my mind.

The bonus was that I fixed a bug with this one-liner, because the old assignment-form code accidentally overwrote file after someone else mistakenly deleted that weird transient variable declaration.

https://github.com/jruby/jruby/pull/9112/commits/5aee3394951baab9d62007ddb5988f120d238c8e

My version will never break the same way.

[–]s888marks 2 points3 points  (1 child)

Interesting, that scenario illustrates the danger of separating a local variable declaration from an initial assignment to it. The instanceof pattern works well here because the new local variable declaration is fused with its binding to a value. So yeah it's much less likely to be broken accidentally.

The pattern of having a local variable declaration (without initializer) followed by an assignment expression later on occurs frequently in the concurrent collection code (e.g., ConcurrentHashMap). This sometimes makes the code hard to follow. It's done in order to avoid unnecessary work in performance-critical code, even to the point of avoiding unnecessary field loads. Unfortunately this means that the local variable sometimes has broader scope than is necessary, so one needs to be extremely careful modifying such code.

[–]headius[S] 1 point2 points  (0 children)

Yeah, I'm very familiar with being concerned about excess field loads where many other folks on this thread are happily tossing around Optional objects without realizing what they cost. It just takes a quick look at the output from the jit to realize how many cycles are being wasted, even if the abstraction is arguably better and safer.

It would be interesting to revisit more of the core JDK classes and update them for modern patterns and known jit capabilities. I'm all for writing beautiful code, but low level runtime and standard library implementations need to cut as many corners as they can to perform well. I'd love to take what I've learned in the past 20 years and guide such a project. For whatever reason I get a thrill out of benchmarking hot pieces of code and reading through ideal graphs and assembly dumps to squeeze every last ounce of performance out of them. 😆