[External] : Re: Feedback about LazyConstants API (JEP526)
david Grajales
david.1993grajales at gmail.com
Tue Dec 9 15:23:43 UTC 2025
Hi Maurizio. Understandable. Thank you for the clarification.
Best regards.
El mar, 9 de dic de 2025, 10:18 a.m., Maurizio Cimadamore <
maurizio.cimadamore at oracle.com> escribió:
> Hi David,
> I think what you suggest is outside the scope of the LazyConstant API (as
> Per has already said).
>
> The goal of LazyConstant is to provide an easy to use abstraction for lazy
> initialization that addresses the 90% use case (e.g. deferred
> initialization using a lambda).
>
> There will be another, more imperative API that can be used to build what
> you want.
>
> But what we have learned when working on this project, is that if we
> increase the scope/reach of LazyConstant to include more imperative
> aspects, it ends up with confusion pretty quickly.
>
> The design you proposed was considered -- and rejected. While it holds
> together, the fact that the initialization action provided at creation acts
> now as a "fallback" initialization action, and can be overridden by use
> sites calling computeIfAbsent was deemed surprising and/or confusing.
>
> Regards
> Maurizio
> On 09/12/2025 14:46, david Grajales wrote:
>
> I am glad my feedback was helpful and sparkled such a great discussion. I
> would like to put 2 cents more, looking for these to be helpful.
>
> My main concern with "orElse" is that most of the time (at least for my
> how I would use this API in my job) most of the time I need a reliable way
> to set the constant and use that particular constant along the life cycle
> of the class, **not** declaring an alternative local variable in
> replacement because most of the time there is no good "burned in the code"
> alternatives that I could use . The use cases I have for this API are
> usually about deferred initialization of values that often require some
> time costly operation, some of those may involve calls to external services
> (IO operations) thus having a "burned" constant in these cases is not
> useful. Instead I propose a "computeIfAbsent" (I am not against orElse
> naming) method that allows for alternative downstream conditional
> initialization of the Lazy constant.
>
> private class Bar{
> LazyCosntan<Weather> weatherUrl = LazyCosntant.of(this::checkAndGetWeatherUrl);
>
>
> public Bar(){}
>
> private String checkAndGetWeatherUrl(){
> return Executors.newVirtualThreadPerTaskExecutor()
> .submit(() -> /*Some query to check if the weather server is up*/);
> }
>
> private String checkAndGetAltWeatherUrl(){
> return Executors.newVirtualThreadPerTaskExecutor()
> .submit(() -> /*Some query to check if the alt weather server is up*/);
> }
>
> public Weather getWeather(){
>
> var url = weatherUrl.computeIfAbsent(this::checkAndGetAltWeatherUrl).get();
>
> // logic to get the weather here using the lazy constants// }
>
> public void sendWeather(){
>
> var url = weatherUrl.computeIfAbsent(this::checkAndGetAltWeatherUrl).get();
>
> Executors.newVirtualThreadPerTaskExecutor()
> .submit(() -> /*Send the weather url to somewhere else* using weatherUrl*/);
> }
>
>
> }
>
>
> This pattern is very common, either for a trivial weather or to check or a
> conf and alternatives in case the regular one is not available (for example
> a conf file that may be missing and one may set a method that downloads it
> from a remote server first in case it is absent)
>
> So for me the issue is not the concept of "orElse" but how the current
> implementation returns me an alternative value instead of SETTING an
> alternative value in case the regular attempt fails or hasn't been called
> still because the program followed an alternative path before the obvious
> regular initialization path. If the orElse (or any other name that fits)
> changes the behaviour to set a value instead of returning something it
> would be the best approach IMHO.
>
>
>
>
> El mar, 9 dic 2025 a la(s) 9:13 a.m., Anatoly Kupriyanov (
> kan.izh at gmail.com) escribió:
>
>> My idea is not an optional *interface*, but an interface for something
>> which is convertible to the Optional *type*. In other words, neither the
>> LazyConstant nor to ScopedVariable *is not* an optional itself, but
>> could be converted to it uniformly.
>> Something like this:
>>
>> interface Optionable<T> {// need to think about the better naming!
>> T orElse(T other);
>>
>> // and maybe even:
>> default Optional<T> asOptional() {
>> return Optional.ofNullable(this.orElse(null));
>> };
>> }
>>
>> and then LazyConstant, ScopedVariable, etc could just implement the
>> interface to unify on the notion of "return a user-provided value
>> if some condition isn't met". Sounds like a decent path to abolish nulls.
>>
>> But I feel I am overthinking this...
>>
>>
>> On Tue, 9 Dec 2025 at 13:35, Red IO <redio.development at gmail.com> wrote:
>>
>>> I initially thought I agree with your statement that orElse is a common
>>> pattern in the jdk. But then I failed to come up with a second example. I
>>> then searched the jdk github repo for the method. And I only found Optional
>>> and it's specializations and ClassHierarchyResolver.
>>> So I would suggest yes, it's an often used method ... of the Optional
>>> class. Not many apis seem to expose it. The case of exposing an accessor
>>> that returns an Optional on the other hand is incredibly common across the
>>> jdk. This is exactly the case Optional was designed for. In this sense
>>> Optional is the "Interface" you are suggesting.
>>>
>>> My main argument against reusing orElse here is that the context is a
>>> completely different one.
>>> An Optional orElse method is a pure function that always returns the
>>> same value. It signals that the value is not there.
>>> LazyConstant is different in this regard. The LazyConstant orElse is not
>>> pure at all. It depends on rather someone else already initialized the
>>> value or not. It signals that the value is not there YET.
>>>
>>> Great regards
>>> RedIODev
>>>
>>>
>>>
>>> On Tue, Dec 9, 2025, 13:51 Anatoly Kupriyanov <kan.izh at gmail.com> wrote:
>>>
>>>> Right, the ScopedValue is another good example I've forgotten. In that
>>>> case I am even more inclined to keep the `orElse` as it looks like a
>>>> repeating pattern across JDK libraries. Consistency is the way to go!
>>>> And maybe even consider having a new interface for the method to make
>>>> this pattern explicit?..
>>>>
>>>> I am glad that `orElseSet` is removed, the side-effecting is bad; also
>>>> in other parts of JDK we already have `computeIfAbsent` for the same idea.
>>>> I did not hear about it, and yeah, sounds like the source of this confusion.
>>>>
>>>>
>>>> On Tue, 9 Dec 2025 at 12:05, Maurizio Cimadamore <
>>>> maurizio.cimadamore at oracle.com> wrote:
>>>>
>>>>>
>>>>> On 09/12/2025 11:59, Anatoly Kupriyanov wrote:
>>>>> > To be honest, I don't really see why this method causes such
>>>>> confusion.
>>>>>
>>>>> In part I agree. E.g. when we added this, what we had in mind was just
>>>>>
>>>>>
>>>>> https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/ScopedValue.html#orElse(T)
>>>>>
>>>>> E.g. other APIs have `orElse` method that return a user-provided value
>>>>> if some condition isn't met.
>>>>>
>>>>> I believe the problem we're discussing here is likely also related to
>>>>> the fact that the API used to have a side-effecting `orElseSet`, which
>>>>> is now removed, and I wonder if, because of that, folks are reading
>>>>> too
>>>>> much into what orElse does?
>>>>>
>>>>> Maurizio
>>>>>
>>>>>
>>>>
>>>> --
>>>> WBR, Anatoly.
>>>>
>>>
>>
>> --
>> WBR, Anatoly.
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20251209/06161faa/attachment-0001.htm>
More information about the amber-dev
mailing list