bye stable values, enter lazy constants
    Maurizio Cimadamore 
    maurizio.cimadamore at oracle.com
       
    Thu Oct  2 08:17:53 UTC 2025
    
    
  
On 02/10/2025 04:05, Sergey Bylokhov wrote:
> On 9/30/25 02:27, Maurizio Cimadamore wrote:
>> In the new API, LazyConstant.of() is no longer present (unlike
>> StableValue::of), so I don't think this is an issue (e.g. you _have_ to
>> pass a lambda).
>
> +1
>
>> ```
>> class Foo {
>>      private static final LazyConstant<Logger> LOGGER =
>> LazyConstant.of(() -> makeLogger(Foo.class));
>>
>>      static Logger getLogger() {
>>          return LOGGER.get();
>>      }
>> }
>> ```
>>
>> The "problem" here is that you have a LOGGER field, and the
>> implementation of Foo can access that field directly, w/o calling
>> `getLogger`. Fine. But what can you do with LOGGER if not calling its
>> get() method (which is also what the getter does) ? I'd like to
>> understand the concern better here.
>
> Even if the LazyConstant field is marked as private, it is still 
> accessible from within the scope of the class. That means it can be 
> read and therefore initialized by other methods in the same class, or 
> even externally via JNI/reflection/etc. This can trigger the 
> evaluation of the lambda expression passed to the lazy factory, 
> causing the value to be computed and stored, even if the intended 
> public factory method was never called.
>
> This is a problem if initialization order matters. For example, say 
> Foo.getInstance() is supposed to initialize(and skip) 
> LOGGER/LOGGER1/LOGGER2/etc in a specific order. If the class has 
> multiple loggers (for terminal, filesystem, network, etc.), how can we 
> prevent accidental access to the wrong logger? How do we make sure 
> direct access does not allow premature or out-of-order initialization?
>
> I am not saying this feature is absolutely necessary, but it is 
> something we do get to some extent with the holder pattern.
Yep. Thinking more about this, if we ever did the idea you suggested the 
other day (e.g. declaring static fields inside a method), then you could 
have tighter scoping
e.g.
```
Logger getLogger() {
     static LazyConstant<Logger> LOGGER = LazyConstant.of(...);
     return LOGGER.get();
}
```
(Now, while I think it's useful to have static _classes_ inside a 
method, I think having a static field in there might be a bit confusing, 
as it looks like a local variable, but isn't really -- it's a field. So 
whether that's a good idea or not will have to be assessed separately)
My main point here is that there are (as you have noticed) possible 
general ways to ameliorate the situation which, if provided, 
LazyConstant could benefit from immediately.
>
>>>  - Handling exceptions more robustly than the Holder idiom
>>
>> If an exception is thrown while computing the value is never set on the
>> lazy constant -- meaning the next call to `get` will re-generate the
>> same exception. With holder idiom one of the issue is that exceptions
>> are thrown during initialization of the holder class, which can
>> sometimes add confusion.
>
> It is the main improvement over the holder, and I really like it!
> This is one of the reason the holder cannot be used in many places in 
> the JDK.
Cool - thanks for the feedback. Getting semantics of exceptions correct 
with a lazy API is always a bit tricky...
Maurizio
    
    
More information about the leyden-dev
mailing list