<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p><br>
</p>
<div class="moz-cite-prefix">On 29/09/2025 21:39, Sergey Bylokhov
wrote:<br>
</div>
<blockquote type="cite" cite="mid:39b68d9b-7eeb-4c12-aac3-dd85d5f6a01f@amazon.com">On
9/29/25 12:51, Maurizio Cimadamore wrote:
<br>
<blockquote type="cite">The point remains: lazy doesn't imply
"only one" -- so, I don't buy that
<br>
Lazy<T> is "good enough" (although I agree it's much
shorter to type --
<br>
which is, I think, the real argument here?)
<br>
</blockquote>
<br>
I have two points about this (and yes, naming is hard):
<br>
- First, why does "lazy" not imply "only once"? We already have
an example of such an API: records. Does the word "record"
explicitly imply that its components can only be assigned once? We
implemented and documented it that way. Similarly, we can document
the behavior for the new interface/class to clarify that laziness
also means "stability".
<br>
</blockquote>
Record components are not "lazy" -- they are assigned at record
creation. Also, record is a language feature. Sure there's an API as
well (Record) but it's very unlikely for users to use that directly.
So I'm not sure how much of a precedent that is.<br>
<blockquote type="cite" cite="mid:39b68d9b-7eeb-4c12-aac3-dd85d5f6a01f@amazon.com"> -
Second, the main argument here is about the "Constant" part. The
API is being compared to the final keyword and is positioned as an
improvement, since it allows lazy initialization while still
enabling the JVM to optimize everything. This optimization
capability is emphasized by the "Constant" in the name. But if the
field itself is not declared final, that undermines the whole
argument.
<br>
</blockquote>
<p>Final fields need to be initialized in the constructor/static
initializer. Mutable fields can be initialized wherever you want,
but then they don't get any stability guarantees. Lazy constants
define (_through an API_) a holder for a new kind of field that
can be initialized lazily, but only once (so, it is stable).</p>
<p>The fact that, to get perfect runtime performance you need final
on the declaration of the LazyConstant field seems, frankly,
secondary -- and derives from the choice of modelling this as an
API. Perhaps, in the table where we list the main differences
between final fields, mutable fields and lazy constants we could
drop the column on constant folding.</p>
<p>Aside from that reference, I don't think the JEP is so focussed
on performance and low-level details as you seem to imply? The
only reference to constant folding happens quite late in the game:</p>
<p>> There is, furthermore, mechanical sympathy between lazy
constants and the Java runtime. Under the hood, the content of a
lazy constant is stored in a non-<code>final</code> field
annotated with the JDK-internal <a href="https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/jdk/internal/vm/annotation/Stable.java#L30-L90"><code>@Stable</code></a>
annotation. This annotation is a common feature of low-level JDK
code. It asserts that, even though the field is non-<code>final</code>,
the field’s value will not change after the field’s initial and
only update. This allows the JVM to treat the content of a lazy
constant as a true constant, provided that the field which refers
to the lazy constant is <code>final</code>. Thus the JVM can
apply constant-folding optimizations to code that accesses
immutable data through multiple levels of lazy constants, e.g., <code>Application.orders().getLogger()</code>.</p>
<p>Which seems fair, and even states that the lazy constant field
needs to be final for this to happen (as you pointed out).<br>
</p>
<blockquote type="cite" cite="mid:39b68d9b-7eeb-4c12-aac3-dd85d5f6a01f@amazon.com">
<br>
<br>
As for the current proposal, it feels somewhat unnatural that the
API is split between LazyConstants and Map/List. I think it needs
some time and experimentation to see how it plays out in practice.
<br>
</blockquote>
Sure, we need to see how this plays out.<br>
<br>
<blockquote type="cite" cite="mid:39b68d9b-7eeb-4c12-aac3-dd85d5f6a01f@amazon.com">
<br>
<br>
<blockquote type="cite">When you have lots of fields, using a lazy
list provides quite a big win
<br>
compared to having separate holders (we made experiments with
our
<br>
jextract tool which demonstrate this) -- because you can have a
single
<br>
lambda/class for _all_ the elements. So you get the same
performance as
<br>
having one holder class for each element, w/o really having one
holder
<br>
for each element.
<br>
</blockquote>
<br>
This argument is overly focused on performance. It suggests that
exposing many unrelated fields in a class is acceptable if it
leads to better performance. While that might be beneficial for
generated code, in manually written code, clarity might be more
important than performance.
<br>
</blockquote>
<p>I was replying to your own performance observation that
LazyConstant and holder classes are the same. The answer is, I
think, it depends. There will be cases where you have completely
unrelated fields, and so you don't want to model these fields with
a list/map -- there will be other cases where your class has 42
similar method handles, one for each entity it wants to represent
-- at which point the advantage of representing each field
separately seems much less obvious. The LazyConstant API gives you
both options.</p>
<blockquote type="cite" cite="mid:39b68d9b-7eeb-4c12-aac3-dd85d5f6a01f@amazon.com">
<br>
I hope we can achieve both goals: good performance and proper
encapsulation.
<br>
</blockquote>
<p>You need to define what you mean by "encapsulation" here -- we're
talking about private fields in a class after all, so it's not
entirely clear to me what do you mean by "expose" and
"encapsulation".</p>
<p>I believe what you are after is a way to write the field
declaration as regular field declaration (perhaps with a keyword
sprinkled on top), and let the compiler worry about desugaring the
code in a way that doesn't need an holder class per field.</p>
<p>Fair, but we're in language territory again.</p>
<p>Maurizio<br>
</p>
</body>
</html>