Lazy statics (was: Feedback / query on jextract for Windows 10)
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Wed Feb 3 18:53:57 UTC 2021
Thanks for capturing previous discussions in one place. Some comments
below:
> Without painting the bikeshed, let me point out that there are two
> possible user models for capturing laziness: lazy fields and cached
> methods. Lazy fields are the more obvious:
>
> __lazy static final String s = computeABigString();
>
> but we could frame this equivalently as
>
> __cached static String computeABigString() { ... }
>
> There are pros and cons to each, but this is largely a user-model
> question about the story we tell. Saying this is a field, vs a
> cached method, sends a slightly different message.
Yes, and indeed we are flexible here: jextract does not exposes its
constants as fields, but as methods (which are statically imported by
the client class).
I might add that there is another option:
__const String s = computeABigString();
Whereby the semantics is simply that this thing is aggressively folded
wherever it's used. E.g. there's no getfield, no methodcall - it's a
_constant_ access, and javac has generated some code to access that
constant in place.
This comes with other pros and cons; on the one side, it clearly
captures what's going on: a free floating constant that can be
initialized wherever and from whomever (and also makes the ties with
static-ness more obvious). On the other hand, folding across
compilation units is a behavior we get right now with certain kind of
static final fields, and we're probably not 100% sure we like that
model (but maybe __const could be private to a class, a la
`withfield`).
>
> Separately, there's a hidden possible requirement we should try to be
> explicit about: whether we care about binary compatible migration for
> _public_ lazy static fields. If we have today:
>
> public static final String s = ...
>
> and some *other* class accesses the field, there will be `getstatic`
> instructions in the wild that expect the field to be there. But,
> this would constrain the ability to translate a read of a lazy static
> as invoking a method whose body does an LDC, which might be a
> preferable translation. I am not expressing an opinion on whether
> this is a requirement or not, as much as calling it out as something
> we could _choose_ to take on, or not, with full awareness of the
> tradeoffs.
>
> Reframing as caching makes it more obvious that we have to be clear
> about what guarantees we are offering, especially in the instance
> case; are we guaranteeing to execute the method no more than once, or
> is it OK for multiple threads to race to initialize the cached
> value? What visibility guarantees do we make?
So, it seems to me that caching is a bit clearer in setting
expectations when it comes to migrating away from a "final static"
field, as well as capturing the throwy nature of these things.
The point you raise about thread racing to init an instance constant is
a well taken one, and I think it's a pretty bad problem to have to
solve - of course we have the tools (atomic access, etc.) but seems
expensive-ish, and the performance model is probably not very
transparent from the client side.
Maurizio
More information about the panama-dev
mailing list