lazy statics design notes
john.r.rose at oracle.com
Sat Mar 2 19:37:35 UTC 2019
On Mar 1, 2019, at 3:47 AM, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:
> From a technical perspective I don't think there's any issue. You get condy semantics, which, as you say, is well defined w.r.t. cycles and laziness etc.
> From a language perspective I see an issue if we expect, as we said, that most people will just jump in and replace 'static' with 'lazy-static'. That is gonna have all sorts of behavioral incompatibilities.
The first time someone gets an error because the value of the lazy-static is null,
they will say "those idiots", etc. Whereas we want them to think of adding laziness
as a simple, foolproof way to get certain kinds of performance improvements.
This is a good point, and may overcome my arguments. It will push the friction
forward in time, to the place where we add non-static lazies; at that point we
will have a less pleasant choice between transactional memory and reserving
the value I am asking we reserve *now*.
(BTE, this is a classic example of something that looks great from the VM looking
upward doesn't look so great from the user model looking downward.)
So, I want to defend my proposal a little more, not only by saying we'll pay
a cost later if we don't reserve the value now, but also by noting that your
point about "all sorts of behavioral incompatibilities" applies more evenly
than you may think, to both proposals (reserve a value, vs. don't reserve).
Even if you allow the full range of values, including null, there will be
all sorts of more subtle behavioral incompatibilities just from changing
the order in which statics are initialized, and (what's more) making the
order dynamically data dependent. The bugs that folks will run into
from "going lazy" will be bootstrap ordering bugs, causing null
pointer exceptions (typically) when one initializer needs access to
a non-lazily initialized static in some other class.
Bootstrap errors happen all the time when there are delicate inter-class
initialization dependencies. Today we see it when static initializers
recurse into themselves via another class. Tomorrow we will see it
whenever there is a mix of lazy and non-lazy initialization.
So, I don't buy that non-reservation of null is going to especially improve
the user experience. It will remove one moderately sharp edge, leaving
some sharper ones. I'm saying the reserved value is "moderately" sharp,
because it is relatively easy to diagnose, compared with bootstrap ordering
bugs, which are always non-local in nature.
And, just to repeat another bit: We have already bitten the "no nulls" bullet
with Optional. We are telling users that, for certain constructs, nulls are
out of policy. That too could cause "all sorts of incompatibilities", making
it hard to refactor to use the new feature (Optionals). So it feels like a
defensible move here also. "Lazies are a language supported form of
optionals which automatically change state from empty. You can't put
nulls in them." What's hard about that? Especially if we make reflection
and/or method handle versions which return an actual Optional if the
user wants to do a non-triggering sense of the state.
Anyway, on balance, I'd still prefer to make lazies like optionals, and
then continue to align them that way when we get to non-static lazies
and (if we go there) use-site lazies.
I didn't say "if we go there" for non-static lazies because they are so
freaking useful *today*, under the disguise of @Stable. We'll want to
More information about the valhalla-spec-observers