Hi Maurizio. Understandable. Thank you for the clarification. Best regards.
El mar, 9 de dic de 2025, 10:18 a.m., Maurizio Cimadamore < [email protected]> 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 ( > [email protected]) 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 <[email protected]> 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 <[email protected]> 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 < >>>> [email protected]> 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. >> >
