Lazy statics (was: Feedback / query on jextract for Windows 10)

Maurizio Cimadamore maurizio.cimadamore at
Wed Feb 3 18:53:57 UTC 2021

Thanks for capturing previous discussions in one place. Some comments

> 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

> 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.


More information about the panama-dev mailing list