So, it is nice that folks seem to agree that LazyConstant should only compute 
and initialize its contents from the Supplier/lambda given at declaration time. 
The orElse method seems to blur the contours of LazyConstant , and so, as 
previously said, we might consider removing the method altogether in the next 
preview.

It is also a fact that many have identified a need for "something else more 
low-level" that supports a more imperative programming model when working with 
constants that are lazily set. We do not rule out that such a thing might 
appear in a future JDK version.

Best, Per

Confidential- Oracle Internal
________________________________
From: David Alayachew <[email protected]>
Sent: Friday, December 5, 2025 2:51 PM
To: Red IO <[email protected]>
Cc: david Grajales <[email protected]>; Per-Ake Minborg 
<[email protected]>; amber-dev <[email protected]>; core-libs-dev 
<[email protected]>
Subject: [External] : Re: Feedback about LazyConstants API (JEP526)

Caveat -- I have only used the Java 25 version of this library.

I agree that the name orElse() is not intuitive. It was made more intuitive by 
the existence of orElseSet(). In its absence, changing the name makes sense.

Though, I'm definitely open to just removing the method. This is easy enough to 
accomplish ourselves. Would prefer a rename though.

On Fri, Dec 5, 2025, 8:32 AM Red IO 
<[email protected]<mailto:[email protected]>> wrote:
Hi David,
As par already said the orElse method doesn't initializes the LazyConstant.
It just checks rather the value is init and if not calls the supplier to get a 
substitute for the missing constant.
Example:
LazyConstant<String> x = LazyConstant.of(() -> "Const");
var uninit1 = x.orElse(() -> "substitute 1");
var uninit2 = x.orElse(() -> "substitute 2");
var init1 = x.get();
var init2 = x.orElse(() -> "substitute 3");
uninit1 and uninit2 get the substitute 1/2
And init1 and init2 get Const.

This is surprising if you expect it to be a way to init it with an alternative 
value.

My suggestion would to make the separation clear and allow for another use case 
by spliting this api in 2 parts:
One class LazyConstant
Takes a Supplier in static factory and exposes get()

And
Class LazyInit
Which takes no arguments in the static factory and takes a supplier in the get 
method that gets called when get is called for the first time.
In this case the source for the constant can be any piece of code that has 
access to the LazyConstant. This might be desired in some cases. In cases where 
it's not the other version can be used.

This split makes it clear from which context the constant is initialized from 
(consumer or at declaration)

Mixing those 2 or having methods that appear to do this is rather confusing.



One solution for the "i might not want to init the constant" case the "orElse" 
method is meant to be is to have a method "tryGet" which returns Optional 
instead. This makes it clear that the value might not be there and is not 
initialized when calling the method. Nobody expects to init the constant when 
calling orElse on a returned Optional.

My 2 suggestions here are completely independent and should be viewed as such.

Great regards
RedIODev

On Fri, Dec 5, 2025, 13:55 david Grajales 
<[email protected]<mailto:[email protected]>> wrote:
HI Per. I pleasure to talk with you.

You are right about one thing but this actually makes the API less intuitive 
and harder to read and reason about.

LazyConstant<String> foo = LazyConstant.of(() -> "hello");

void main() {
    if (someCondition()) {// asume false
        foo.get();
    }
    foo.orElse("hello2"); // ...

    println(foo.get()); // This prints "hello"
}

But if one assigns foo.orElse("hello2") to a variable, the variable actually 
gets the "hello2" value.

void main() {
    if (someCondition()) {// asume false
        foo.get();
    }
    var res = foo.orElse("hello2"); // ...
    var res2 = foo.orElse("hello3");
    println(res); // This prints "hello2"
    println(res2);//This prints "hello3"
}

This is actually even more confusing and makes the API more error prone. I 
personally think once initialized the lazy constant should always return the 
same value (maybe through the .get() method only), and there should not be any 
possibility of getting a different values from the same instance either in the 
.of() static method or in any hypothetical instance method for conditional 
downstream logic.  I guess one could achieve the latter with the static factory 
method through something like this (although less elegant)

private class Bar{
    private final LazyConstant<String> foo;
    private Bar(Some some){

        if(some.condition){
            foo = LazyConstant.of(() -> "hello");
        }else {
            foo = LazyConstant.of(() -> "hello2");
        }
    }
}

Thank you for reading. This is all I have to report.

Best regards.



El vie, 5 dic 2025 a la(s) 6:05 a.m., Per-Ake Minborg 
([email protected]<mailto:[email protected]>) escribió:
Hi David,

Thank you for trying out LazyConstant and providing feedback. That is precisely 
what previews are for!

If you take a closer look at the specification of LazyConstant::orElse, it says 
that the method will never trigger initialization. And so, you can actually be 
sure that in your first example, foo is always initialized to "hello" (if ever 
initialized). It is only if foo is not initialized that the method will return 
"hello2" (again, without initializing foo). This is similar to how Optional 
works.

It would be possible to entirely remove the orElse() method from the API, and 
in the rare cases where an equivalent functionality is called for, rely on 
LazyConstant::isInitialized instead.

Best, Per


Confidential- Oracle Internal
________________________________
From: amber-dev <[email protected]<mailto:[email protected]>> 
on behalf of david Grajales 
<[email protected]<mailto:[email protected]>>
Sent: Friday, December 5, 2025 5:38 AM
To: amber-dev <[email protected]<mailto:[email protected]>>; 
[email protected]<mailto:[email protected]> 
<[email protected]<mailto:[email protected]>>
Subject: Feedback about LazyConstants API (JEP526)

Dear Java Dev Team,

 I am writing to provide feedback and two specific observations regarding the 
LazyConstant API, which is currently a preview feature in OpenJDK 26.

 I appreciate the API's direction and I think it's a good improvement compared 
to its first iteration; however, I see potential for improved expressiveness, 
particularly in conditional scenarios.


1. Proposal: Zero-Parameter `LazyConstant.of()` Overload:

Currently, the mandatory use of a factory method receiving a `Supplier` (due to 
the lack of a public constructor) can obscure the expressiveness of conditional 
or multiple-value initialization paths. **The Issue:** When looking at the 
declaration:

LazyConstant<String> foo = LazyConstant.of(() -> "hello");

the code gives the strong, immediate impression that the value is always 
initialized to "hello". This makes it difficult to infer that the constant 
might ultimately resolve to an alternative value set later via orElse() or 
another conditional path, especially when skimming the code:

LazyConstant<String> foo = LazyConstant.of(() -> "hello"); // When skimming the 
code it's not always obvious that this may not be the actual value

void main() {
  if (someCondition()) {
          foo.get(); // Trigger initialization to "hello"
 }
  // If someCondition is false, the final value of foo is determined here:
  var res1 = foo.orElse("hello2"); // ...
}

My Suggestion: I propose introducing a zero-parameter overloaded static factory 
method of():

LazyConstant<String> foo = LazyConstant.of();

This form explicitly communicates that the constant is initialized to an 
unresolved state, suggesting that the value will be determined downstream by 
the first invocation of an initialization/computation method.

LazyConstant<String> foo = LazyConstant.of(); // Clearly unresolved
  void main() {
  if (someCondition()) {
      foo.orElse("hello");
 }
  var res1 = foo.orElse("hello2"); // ...
}

This is specially useful for clarity when one has conditional initialization in 
places such as the constructor of a class. For example


private class Bar{
    LazyConstant<String> foo = LazyConstant.of();
    private Bar(Some some){
        if(some.condition()){
            foo.orElse("foo");
        }
        foo.orElse("foo2");
    }

    String computeValue() {
        return "hello";
    }

    String computeValue2(){
        return "hello2";
    }
}

2. Method Naming Suggestion and and supplier in instance method for consistency 
in the API

My second, much more minor observation relates to the instance method orElse(T 
t).

While orElse fits a retrieval pattern, I personally feel that compute or 
computeIfAbsent would better express the intent of this method, as its primary 
function is not just to retrieve, but to trigger the computation and set the 
final value of the constant if it is currently uninitialized. Also, as the 
factory of() has a supplier i think this instance method should also receive a 
Supplier, This not only keeps the API consistent in the usage but makes more 
ergonomic the declaration of complex initialization logic inside the method.


private class Bar{
    LazyConstant<InitParams> foo = LazyConstant.of(InitParam::default); // 
Under the current API this is mandatory but in reality the value is set in the 
constructor, default is never really used.
    private Bar(Some some){
       foo.compute(some::executeCallToCacheDBAndBringInitializationParams) 
//Real configuration happens here

    }
}

This last it's very common for initialization of configuration classes and 
singletons.


Thank you so much for your attention, I hope you find this feedback useful.

Always yours. David Grajales

Reply via email to