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]) 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]> on behalf of david
> Grajales <[email protected]>
> *Sent:* Friday, December 5, 2025 5:38 AM
> *To:* amber-dev <[email protected]>; [email protected] <
> [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
>