RFR: 8351565: Implement JEP 502: Stable Values (Preview) [v25]

Maurizio Cimadamore mcimadamore at openjdk.org
Wed Apr 2 09:45:52 UTC 2025


On Tue, 1 Apr 2025 13:27:34 GMT, Per Minborg <pminborg at openjdk.org> wrote:

>> Implement JEP 502.
>> 
>> The PR passes tier1-tier3 tests.
>
> Per Minborg has updated the pull request incrementally with two additional commits since the last revision:
> 
>  - Add lazy toSting for StableMap::values
>  - Make toString for reversed and sublist lazy

src/java.base/share/classes/java/lang/StableValue.java line 257:

> 255:  * which are held by stable values:
> 256:  * {@snippet lang = java:
> 257:  * public final class DependencyUtil {

I think the fibonacci example is great -- and is probably enough for this section. We also had, at some point, a nice ASCII art of the computations involved in the fibonacci, which might be useful to illustrate your claim re. "dependency graph". Do you think you can recover that ?

src/java.base/share/classes/java/lang/StableValue.java line 327:

> 325:  * (e.g. {@linkplain #trySet(Object) trySet()})
> 326:  * {@linkplain java.util.concurrent##MemoryVisibility <em>happens-before</em>}
> 327:  * any subsequent read operation (e.g. {@linkplain #orElseThrow()}).

Maybe we should clarify that a write of V happens before a read that can see that can see that V. E.g. a successful `trySet` doesn't happen before _any_ `orElseThrow` _in general_ -- (because `orElseThrow` can also throw -- in which case you know you arrived too early). Also, there's operations in there like `orElseSet` which both get and set -- so perhaps things should be specified a bit more -- e.g. maybe we should talk about a successful read operation as:

* `orElseThrow` that doesn't throw
* `orElse` which dosn't return the fallback value
* `orElseGet` that doesn't run the provided supplier

We can also talk about a succseful write operation:

* a `trySet` which returns true
* a `setOrThrow` that doesn't throw
* an `orElseSet` that runs the supplier

Then we can say that a _successful_ write operation happens before a _successful_ read operation.

src/java.base/share/classes/java/lang/StableValue.java line 371:

> 369: 
> 370:     /**
> 371:      * {@return {@code true} if the content was set to the provided {@code value},

I find this description a bit confusing -- as written it almost looks like a predicate -- e.g. test if this stable value is set with the value I'm providing. But the important thing here is the side-effect -- so I feel the javadoc for this method should be much less about what this method returns, and much more about what the method actually does. (`setOrThrow` seems to be better in this respect)

src/java.base/share/classes/java/lang/StableValue.java line 378:

> 376:      * @param value to set
> 377:      */
> 378:     boolean trySet(T value);

This can probably throw `IllegalStateException` too right -- e.g. if used inside a supplier passed to `orElseSet` ?

src/java.base/share/classes/java/lang/StableValue.java line 416:

> 414:      * When this method returns successfully, the content is always set.
> 415:      * <p>
> 416:      * This method will always return the same witness value regardless if invoked by

will always return/always returns (more direct)

src/java.base/share/classes/java/lang/StableValue.java line 435:

> 433:      *
> 434:      * @param value to set
> 435:      * @throws IllegalStateException if the content was already set

The javadoc speaks about "a stable value is set", and not "content is set". Make sure we're using terminology consistenty

src/java.base/share/classes/java/lang/StableValue.java line 461:

> 459:      * An unset stable value has no content.
> 460:      * <p>
> 461:      * The returned stable value is not {@link Serializable}.

I find the claim about serializable a bit odd here. Perhaps in some `implSpec`/`apiNote` at the toplevel?

src/java.base/share/classes/java/lang/StableValue.java line 507:

> 505:      * @param <T>      the type of results supplied by the returned supplier
> 506:      */
> 507:     static <T> Supplier<T> supplier(Supplier<? extends T> original) {

I think that here and in all other functional/collection factories, we should document that `toString` will never cause a value to be computed.

src/java.base/share/classes/java/lang/StableValue.java line 591:

> 589:      * <p>
> 590:      * The returned list is an {@linkplain Collection##unmodifiable unmodifiable} list
> 591:      * whose size is known at construction. The list's elements are computed via the

s/"is known at construction"/`{@code size}` ?

src/java.base/share/classes/java/lang/StableValue.java line 603:

> 601:      * caller and no value for the element is recorded.
> 602:      * <p>
> 603:      * The returned list and its {@link List#subList(int, int) subList} views implement

Perhaps the most important fact to note here is that the returned lists via `subList` and friends are _also_ stable lists!

src/java.base/share/classes/java/lang/StableValue.java line 657:

> 655:      * @param <V>    the type of mapped values in the returned map
> 656:      */
> 657:     static <K, V> Map<K, V> map(Set<K> keys,

Like `List`, a map can also generate other kinds of collections:
1. an entry set (`Map::entrySet`)
2. a key set (`Map::keySet`)
3. a value set (`Map::values`)

We should make it clear that calling (1) and (3) will result in materializing the values for the map -- we do not have "lazy" views for such sets.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024400960
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024413931
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024425037
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024438670
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024431337
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024442624
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024445136
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024469913
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024451560
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024454122
PR Review Comment: https://git.openjdk.org/jdk/pull/23972#discussion_r2024461588


More information about the core-libs-dev mailing list