<div dir="ltr"><div>I see the ask as slightly different from stable values. Stable values are really two things - a compile time constant that can be inlined and is always lazily initialized exactly once. This ask is for the second part - being able to lazily initialize a value with the same exactly once guarantees without the restriction that the keys must be known at compile time. I have personally used Guava's Suppliers.memoize(Supplier<T> s) or even ConcurrenthashMap's computeIfAbsent for my use-cases and in those I didn't really care about inlining/folding, just the lazy aspect of it.</div><div><br></div><div>To me it is not a huge deal of not having a language or even a standard Java API for it; I have managed without it so far.</div><div><br></div><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div>Regards<br></div><div>Swaranga</div></div></div></div><br></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Tue, Sep 2, 2025 at 4:15 PM Maurizio Cimadamore <<a href="mailto:maurizio.cimadamore@oracle.com">maurizio.cimadamore@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>
<div>
<p>Hi David,<br>
Thanks for your feedback.</p>
<p>The factories that we provide, like StableValue::list and
StableValue::map cover common cases where the list/map elements
are known upfront, but should be computed lazily.</p>
<p>In other words you might think of these factories as lazy
variants of List::of and Map::of. Both kinds of factories return
an unmodifiable collection -- that is a collection whose size is
fixed, and that rejects update operations.</p>
<p>I understand that you would like to create a "stable" map, whose
key/values are not known upfront -- more specifically, where the
keys are only known dynamically.</p>
<p>I believe in these cases the "win" for using a stable map in the
first place is much less obvious. If the map can grow dynamically
(e.g. because you don't know how many entries you might be adding
to it) you are probably looking at an implementation that has some
way to "resize" itself -- which makes using something like a
stable construct much harder. For instance, adding new entries on
a map might cause the underlying array of buckets to be
reallocated, and existing entries to be rehashed in the new
(larger) bucket array. This means that the bucket array itself
will need to be updated several times during the lifecycle of the
map, making it not stable (remember: stable means "updated at most
once").</p>
<p>If some constraints are relaxed, e.g. maybe you know how many
entries you are going to add in your map -- that might make the
problem easier, as now we're back in a situation where we now the
size of the underlying storage. For instance one can have a
specialized hash table implementation backed by a linear array (of
an appropriate size), and then use linear probing to store entries
in the linear array. Since the size is bounded, the size of the
entries linear array is also bounded, and we can then make that
linear array stable (e.g. use a stable list). </p>
<p>Since such a "fixed size" hash map would be quite specialized, we
did not see yet enough motivation for adding it to the JDK --
especially given that developers should be able to define such
constructs on top of the StableValue API (in fact _all_ the
existing provided factories are defined in terms of the Stable
Value API).</p>
<p>But it's not just about whether the size is known or not -- in
order for the JVM to be able to apply any sort of constant-folding
optimization to the map access, you need the key to be a constant
(e.g. either some compile-time constant, or the value of a static
final field, or the contents of some other stable value). Only
then we can fold the entire map access expression (if we're
lucky). But in the example you provide, the key provided to
Map::get is just a random class name you get from the current
stack. So there's very little for the JIT to optimize here. If the
input (the key) is not known, then the access expression
(Map::get) cannot be optimized.<br>
</p>
<p>In other words, the case of a fully dynamic list/map that you
propose just doesn't seem a great fit for stability, in the sense
that you likely won't get any performance improvement (over a
concurrent hash map) by using some sort of stable map there.</p>
<p>Maurizio<br>
</p>
<p><br>
</p>
<div>On 02/09/2025 02:45, david Grajales
wrote:<br>
</div>
<blockquote type="cite">
<div dir="ltr"><br>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">---------- Forwarded message
---------<br>
De: <strong class="gmail_sendername" dir="auto">david
Grajales</strong> <span dir="auto"><<a href="mailto:david.1993grajales@gmail.com" target="_blank">david.1993grajales@gmail.com</a>></span><br>
Date: lun, 1 sept 2025 a la(s) 8:43 p.m.<br>
Subject: Feedback about StableValues(Preview)<br>
To: <<a href="mailto:core-libs-dev@openjdk.org" target="_blank">core-libs-dev@openjdk.org</a>><br>
</div>
<br>
<br>
<div dir="ltr">
<p>Subject: Feedback and Questions on JEP 8359894 - Stable
Values API</p>
<p>Dear Java core-libs development team,</p>
<p>Please accept my sincere gratitude and compliments for
your ongoing dedication to improving the Java platform.
The continuous innovation and thoughtful evolution of Java
is truly appreciated by the developer community.</p>
<p>I have been experimenting with the Stable Values API (JEP
8359894) in a development branch of a service at my
company, and I would like to share some observations and
seek your guidance on a particular use case.</p>
<p><br>
</p>
<h2>Current Implementation</h2>
<p>
</p>
<p>Currently, I have a logging utility that follows a
standard pattern for lazy value computation:</p>
<div><br>
</div>
<div>class DbLogUtility {<br>
private static final ConcurrentMap<String,
Logger> loggerCache = new ConcurrentHashMap<>();<br>
<br>
private DbLogUtility(){}<br>
<br>
private static Logger getLogger() {<br>
var className =
Thread.currentThread().getStackTrace()[3].getClassName();<br>
return loggerCache.computeIfAbsent(className,
LoggerFactory::getLogger);<br>
}<br>
public static void logError(){<br>
//.... implementation detail<br>
}</div>
<div>}</div>
<div><br>
</div>
<div>
<h2>Challenge with Stable Values API</h2>
<p>When attempting to migrate this code to use the Stable
Values API, I encountered a fundamental limitation: the
API requires keys to be known at compile time. The
current factory methods (<code>StableValue.function(Set<K>,
Function)</code> and <code>StableValue.intFunction(int,
IntFunction)</code>) expect predefined key sets or
bounded integer ranges.</p>
<p>This design constraint makes it challenging to handle
dynamic key discovery scenarios, which are quite common
in enterprise applications for:</p>
<ul>
<li>Logger caching by dynamically discovered class names</li>
<li>Configuration caching by runtime-determined keys</li>
<li>Resource pooling with dynamic identifiers</li>
<li>Etc.</li>
</ul>
</div>
<div><br>
</div>
<div>
<h2>Questions and Feedback</h2>
<ol>
<li><strong>Am I missing an intended usage pattern?</strong>
Is there a recommended approach within the current API
design for handling dynamic key discovery while
maintaining the performance benefits of stable values?</li>
<li> Would you consider any of these potential
enhancements:
<ul>
<li>Integration of stable value optimizations
directly into existing collection APIs (similar to
how some methods have been added to List and Map
interfaces for better discoverability)</li>
<li>A hybrid approach that provides stable value
benefits for dynamically discovered keys</li>
</ul>
</li>
<li>Do you envision the Stable Values API as primarily
serving compile-time-known scenarios, with dynamic use
cases continuing to rely on traditional concurrent
collections?</li>
</ol>
<div>
<p>Thank you for your time and consideration. I would be
grateful for any guidance or clarification you might
provide on these questions. If there are planned
enhancements or alternative patterns I should
consider, I would very much appreciate your insights.</p>
<p>Best regards, and always yours. </p>
<p>David Grajales Cárdenas. </p>
</div>
</div>
<div><br>
</div>
</div>
</div>
</div>
</blockquote>
</div>
</blockquote></div>