<i18n dev> RFR: 8366178: Implement JEP 526: Lazy Constants (Second Preview)
Chen Liang
liach at openjdk.org
Mon Oct 13 11:51:04 UTC 2025
On Sat, 4 Oct 2025 14:29:08 GMT, ExE Boss <duke at openjdk.org> wrote:
>> Implement JEP 526: Lazy Constants (Second Preview)
>>
>> The lazy list/map implementations are broken out from `ImmutableCollections` to a separate class.
>>
>> The old benchmarks are not moved/renamed to allow comparison with previous releases.
>>
>> `java.util.Optional` is updated so that its field is annotated with `@Stable`. This is to allow `Optional` instances to be held in lazy constants and still provide constant folding.
>
> Getting access to the underlying `StableValue` API with **Lazy Constants** is way too hacky and convoluted (but doable):
> <details>
> <summary>StableVar.java</summary>
>
>
> /*
> * Any copyright is dedicated to the Public Domain.
> * https://creativecommons.org/publicdomain/zero/1.0/
> */
>
> import java.util.NoSuchElementException;
> import java.util.function.Supplier;
>
> import org.jspecify.annotations.NullMarked;
> import org.jspecify.annotations.Nullable;
>
> import static java.lang.System.identityHashCode;
> import static java.util.Objects.requireNonNull;
>
> /// Horrible awful hack to get access to raw stable values in JDK 26+.
> @NullMarked
> public sealed interface StableVar<T> permits StableHacks.StableVarImpl {
> boolean trySet(final T contents) throws NullPointerException, IllegalStateException;
> @Nullable T orNull();
> T orElse(final T other) throws NullPointerException;
> T orElseThrow() throws NoSuchElementException;
> boolean isSet();
> T orElseSet(final Supplier<? extends T> supplier) throws NullPointerException, IllegalStateException;
> void setOrThrow(final T contents) throws NullPointerException, IllegalStateException;
>
> static <T> StableVar<T> of() {
> return StableHacks.newInstance();
> }
> }
>
> /// Encapsulates the actual implementation of `StableValue` on `LazyConstant`
> ///
> /// @author ExE Boss
> @NullMarked
> /*package*/ final @Namespace class StableHacks {
> private StableHacks() throws InstantiationException { throw new InstantiationException(StableHacks.class.getName()); }
>
> private static final String UNSET_SUFFIX = ".unset";
> private static final Object UNSET = new Object() {
> @Override
> public int hashCode() {
> return 0;
> }
>
> @Override
> public String toString() {
> return "unset";
> }
> };
>
> private static final ScopedValue<?> SCOPE = ScopedValue.newInstance();
> private static final Supplier<?> SCOPE_GETTER = SCOPE::get;
>
> /*package*/ static final <T> StableVarImpl<T> newInstance() {
> return new StableValue<>();
> }
>
> /*package*/ sealed interface StableVarImpl<T> extends StableVar<T> {
> }
>
> private record StableValue<T>(
> // Implemented as a record so that the JVM treats this as a trusted final field
> // even when `-XX:+TrustFinalNonStaticFields` is not set
> LazyConstant<T> contents
> ) implements StableVarImpl<T> {
> @SuppressWarnings("unchecked")
> private StableValue() {
> this(LazyConstant.<T>of((Supplier) SCOPE_GETTER));
> }
>
> private StableValue {
> if (contents.isInitialized()) throw new InternalError();
> }
>
> @SuppressWarnings("unchecked")
> private fi...
Hi @ExE-Boss, this new JEP describes how this functionality will be provided in the future:
> Lazy constants cover the common, high-level use cases for lazy initialization. In the future we might consider providing stable access semantics directly, at a lower level, for reference, array, and primitive fields. This would address, for example, use cases where the computing function associated with a lazy constant is not known at construction.
This would be necessary, as there are usage patterns (such as nominal descriptors in ClassFile API) that would benefit from multiple assignment and a stable promoted read.
-------------
PR Comment: https://git.openjdk.org/jdk/pull/27605#issuecomment-3368317631
More information about the i18n-dev
mailing list