Hi Protonull! Thanks for your explanation of the use case (which is interesting), and apologies for my late answer.
As explained in this thread (https://mail.openjdk.org/archives/list/[email protected]/thread/O6UU7O4NTL3I77VWF3DRF64GHUKTWVS3/), we have separated the functional LazyConstant feature and a future, more imperative version. We are currently working on various variants, and we expect all of them to cover your use case. So, stay patient, and hopefully you will get something even better than StableValue in the future. Best, Per Minborg ________________________________ From: Protonull <[email protected]> Sent: Friday, March 20, 2026 2:24 PM To: [email protected] <[email protected]> Subject: [External] : Feedback on LazyConstants (JEP 526) Morning, After having updated to JDK 26, I have some feedback regarding JEP 526: specifically the removal of the "low[er]-level methods". My particular use case is creating mods for a popular block game, which has quite a few competing mod loaders. These mod loaders generally require you to specify a class that extend or implement some kind of interface to handle lifecycle events and so on. Mod developers who wish to support multiple mod loaders typically have a "common" project, which defines the mod's behaviour, and then one or more platform-implementation projects which bridge the gap between common's APIs and the platform's (such as how to implement the registration of key bindings). What mod developers typically do is define an abstract singleton which the platform-impl projects implement and set. Which can look something like the following: public abstract class AbstractExampleMod { protected static AbstractExampleMod instance; public static AbstractExampleMod getInstance() { return instance; } protected void handleEnable() { this.registerKeyBinding(new KeyBinding(Key.R)); } // Example platform-specific method protected abstract void registerKeyBinding(KeyBinding keyBinding); } With a platform-impl class resembling the following: public class PlatformExampleMod extends AbstractExampleMod implements IPlatformMod { public PlatformExampleMod() { if (instance != null) throw new IllegalStateException("instance is already set!"); instance = this; } @Override // from IPlatformMod public void onModEnable() { this.handleEnable(); } @Override // from AbstractExampleMod protected void registerKeyBinding(KeyBinding keyBinding) { Platform.registerKeyBinding(keyBinding); } } Unfortunately, most of the mod loaders do not let you control how or under what circumstances your mod class is constructed: setting the instance occurs once you already have the instance. This was not a problem as StableValue had setOrThrow/trySet, which let you define a placeholder StableValue to set later. This allowed me to update my mods to take advantage of StableValue while only making minor code changes, eg: public abstract class AbstractExampleMod { public static final StableValue<AbstractExampleMod> instance = StableValue.of(); // etc } public class PlatformExampleMod extends AbstractExampleMod implements IPlatformMod { public PlatformExampleMod() { instance.setOrThrow(this); } // etc } While this may seem like a niche use case, this could also apply to values set within a main method, such as setting a particular implementation of an interface to a static constant based on a command-line argument. However, with JEP 526 and the removal of the these methods, there seems to be no other option but to return to the non-final field strategy (or otherwise remaining on JDK 25 preview), which while not the end of the world, is nonetheless rather unfortunate in my opinion. Would it be at all possible to reinstate these methods?
