<div dir="auto">Hi David,<div dir="auto">As par already said the orElse method doesn't initializes the LazyConstant. </div><div dir="auto">It just checks rather the value is init and if not calls the supplier to get a substitute for the missing constant. </div><div dir="auto">Example:</div><div dir="auto">LazyConstant<String> x = LazyConstant.of(() -> "Const");</div><div dir="auto">var uninit1 = x.orElse(() -> "substitute 1");</div><div dir="auto">var uninit2 = x.orElse(() -> "substitute 2");</div><div dir="auto">var init1 = x.get();</div><div dir="auto">var init2 = x.orElse(() -> "substitute 3");</div><div dir="auto">uninit1 and uninit2 get the substitute 1/2</div><div dir="auto">And init1 and init2 get Const. </div><div dir="auto"><br></div><div dir="auto">This is surprising if you expect it to be a way to init it with an alternative value. </div><div dir="auto"><br></div><div dir="auto">My suggestion would to make the separation clear and allow for another use case by spliting this api in 2 parts:</div><div dir="auto">One class LazyConstant </div><div dir="auto">Takes a Supplier in static factory and exposes get() </div><div dir="auto"><br></div><div dir="auto">And</div><div dir="auto">Class LazyInit</div><div dir="auto">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. </div><div dir="auto">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. </div><div dir="auto"><br></div><div dir="auto">This split makes it clear from which context the constant is initialized from (consumer or at declaration) </div><div dir="auto"><br></div><div dir="auto">Mixing those 2 or having methods that appear to do this is rather confusing. </div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">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. </div><div dir="auto"><br></div><div dir="auto">My 2 suggestions here are completely independent and should be viewed as such. </div><div dir="auto"><br></div><div dir="auto">Great regards </div><div dir="auto">RedIODev </div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Fri, Dec 5, 2025, 13:55 david Grajales <<a href="mailto:david.1993grajales@gmail.com">david.1993grajales@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">HI Per. I pleasure to talk with you.<div><br></div><div>You are right about one thing but this actually makes the API less intuitive and harder to read and reason about.</div><div><br></div><div>LazyConstant<String> foo = LazyConstant.of(() -> "hello");<br><br>void main() {<br> if (someCondition()) {// asume false<br> foo.get();<br> }<br> foo.orElse("hello2"); // ...<br><br> println(foo.get()); // This prints "hello"<br>}</div><div><br></div><div>But if one assigns foo.orElse("hello2") to a variable, the variable actually gets the "hello2" value.</div><div><br></div><div>void main() {<br> if (someCondition()) {// asume false<br> foo.get();<br> }<br> var res = foo.orElse("hello2"); // ...</div><div> var res2 = foo.orElse("hello3");<br> println(res); // This prints "hello2"</div><div> println(res2);//This prints "hello3"<br>}<br></div><div><br></div><div>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)</div><div><br></div><div>private class Bar{<br> private final LazyConstant<String> foo;<br> private Bar(Some some){<br><br> if(some.condition){<br> foo = LazyConstant.of(() -> "hello");<br> }else {<br> foo = LazyConstant.of(() -> "hello2");<br> }<br> }<br>}</div><div><br></div><div>Thank you for reading. This is all I have to report. </div><div><br></div><div>Best regards.</div><div><br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">El vie, 5 dic 2025 a la(s) 6:05 a.m., Per-Ake Minborg (<a href="mailto:per-ake.minborg@oracle.com" target="_blank" rel="noreferrer">per-ake.minborg@oracle.com</a>) escribió:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>
<div dir="ltr">
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
Hi David,<br>
<br>
Thank you for trying out LazyConstant and providing feedback. That is precisely what previews are for!<br>
<br>
</div>
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
If you take a closer look at the specification of <code>LazyConstant::orElse,</code> it says that the method will
<i>never trigger initialization.</i> And so, you <i>can</i> actually be sure that in your first example,
<code>foo</code> 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
<code>Optional</code> works.<br>
<br>
It would be possible to entirely remove the <code>orElse()</code> method from the API, and in the rare cases where an equivalent functionality is called for, rely on
<code>LazyConstant::isInitialized</code> instead.<br>
<br>
Best, Per</div>
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<br>
</div>
<div id="m_-8766186915558418911m_-1330836081727153577appendonsend"></div>
<div><br>
<div style="font-family:Calibri;text-align:left;color:rgb(0,0,0);margin-left:5pt;font-size:10pt">
Confidential- Oracle Internal</div>
</div>
<hr style="display:inline-block;width:98%">
<div id="m_-8766186915558418911m_-1330836081727153577divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> amber-dev <<a href="mailto:amber-dev-retn@openjdk.org" target="_blank" rel="noreferrer">amber-dev-retn@openjdk.org</a>> on behalf of david Grajales <<a href="mailto:david.1993grajales@gmail.com" target="_blank" rel="noreferrer">david.1993grajales@gmail.com</a>><br>
<b>Sent:</b> Friday, December 5, 2025 5:38 AM<br>
<b>To:</b> amber-dev <<a href="mailto:amber-dev@openjdk.org" target="_blank" rel="noreferrer">amber-dev@openjdk.org</a>>; <a href="mailto:core-libs-dev@openjdk.org" target="_blank" rel="noreferrer">core-libs-dev@openjdk.org</a> <<a href="mailto:core-libs-dev@openjdk.org" target="_blank" rel="noreferrer">core-libs-dev@openjdk.org</a>><br>
<b>Subject:</b> Feedback about LazyConstants API (JEP526)</font>
<div> </div>
</div>
<div>
<div dir="ltr">Dear Java Dev Team,
<div><br>
</div>
<div> I am writing to provide feedback and two specific observations regarding the LazyConstant API, which is currently a preview feature in OpenJDK 26. </div>
<div><br>
</div>
<div> 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.</div>
<div><br>
</div>
<div><br>
</div>
<div><b>1. Proposal: Zero-Parameter `LazyConstant.of()` Overload:</b> </div>
<div><br>
</div>
<div>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:</div>
<div><br>
</div>
<div>LazyConstant<String> foo = LazyConstant.of(() -> "hello");</div>
<div><br>
</div>
<div>the code gives the strong, immediate impression that the value is <b>always</b> initialized to
<code>"hello"</code>. This makes it difficult to infer that the constant might ultimately resolve to an alternative value set later via
<code>orElse()</code> or another conditional path, especially when skimming the code:</div>
<div><br>
</div>
<div>LazyConstant<String> foo = LazyConstant.of(() -> <span>
"hello"</span>); // When skimming the code it's not always obvious that this may not be the actual value </div>
<div> </div>
<div><span><span>void</span>
<span>main</span><span>()</span>
</span>{ </div>
<div> <span>if</span> (someCondition()) { </div>
<div> foo.get(); <span>// Trigger initialization to "hello"</span> </div>
<div> } </div>
<div> <span>// If someCondition is false, the final value of foo is determined here:</span> </div>
<div> <span>var</span> res1 = foo.orElse(<span>"hello2"</span>);
<span>// ...</span> </div>
<div>}</div>
<div><br>
</div>
<div><b>My Suggestion:</b> I propose introducing a <b>zero-parameter overloaded static factory method</b>
<code>of()</code>:</div>
<div><br>
</div>
<div>LazyConstant<String> foo = LazyConstant.of();</div>
<div><br>
</div>
<div>This form explicitly communicates that the constant is initialized to an <b>
unresolved</b> state, suggesting that the value will be determined downstream by the first invocation of an initialization/computation method.</div>
<div><br>
</div>
<div>LazyConstant<String> foo = LazyConstant.of(); <span>
// Clearly unresolved</span> </div>
<div> <span><span>void</span>
<span>main</span><span>()</span>
</span>{ </div>
<div> <span>if</span> (someCondition()) { </div>
<div> foo.orElse(<span>"hello"</span>); </div>
<div> } </div>
<div> <span>var</span> res1 = foo.orElse(<span>"hello2"</span>);
<span>// ...</span> </div>
<div>}</div>
<div><br>
</div>
<div>This is specially useful for clarity when one has conditional initialization in places such as the constructor of a class. For example</div>
<div><br>
</div>
<div>
<p>private class Bar{<br>
LazyConstant<String> foo = LazyConstant.of();<br>
private Bar(Some some){<br>
if(some.condition()){<br>
foo.orElse("foo");<br>
}<br>
foo.orElse("foo2");<br>
}<br>
<br>
String computeValue() {<br>
return "hello";<br>
}<br>
<br>
String computeValue2(){<br>
return "hello2";<br>
}<br>
}</p>
</div>
<div>
<h3>2. Method Naming Suggestion and and supplier in instance method for consistency in the API</h3>
<p>My second, much more minor observation relates to the instance method <code>orElse(T t)</code>.</p>
<p>While <code>orElse</code> fits a retrieval pattern, I personally feel that <b>
<code>compute</code></b> or <b><code>computeIfAbsent</code></b> would better express the intent of this method, as its primary function is not just to retrieve, but to trigger the computation and
<b>set the final value</b> 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.</p>
<p><br>
</p>
<p></p>
<p></p>
<p></p>
<p>private class Bar{<br>
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.<br>
private Bar(Some some){<br>
foo.compute(some::executeCallToCacheDBAndBringInitializationParams) //Real configuration happens here</p>
<p> }<br>
}</p>
<p>This last it's very common for initialization of configuration classes and singletons.</p>
<p><br>
</p>
<p>Thank you so much for your attention, I hope you find this feedback useful.</p>
<p>Always yours. David Grajales</p>
</div>
</div>
</div>
</div>
</div></blockquote></div>
</blockquote></div>