On Mon, 13 May 2024 12:18:28 GMT, Chen Liang <li...@openjdk.org> wrote:
>> As we need the array in both cases, how would such a solution look like >> without duplicating code? > > I was thinking about changing the StableEnumMap factory to directly take an > EnumSet/BitSet indicating the indices without conversions to full objects and > arrays. Sounds like a good idea. I will fix this. >> I see what you mean with distinct initialization logic. This is not the >> intended use though. >> >> The reason these methods exist is to avoid lambda capturing. Let's say we >> have a `Function<K, V>` we want to apply to a `Map<K, StableValue<V>>`. >> Then, retrieving a `stable = StableValue<V>` and applying >> `stable.computeIfUnset(() -> function.apply(key))` would capture a new >> `Supplier`. Another alternative would be to write imperative code similar to >> what is already in these methods. >> >> What we could do is provide factories for memorized functions (the latter >> described in the draft JEP at the end (https://openjdk.org/jeps/8312611) ) >> even though these are easy to write. >> >> I think what you are proposing is something like this? >> >> >> Map<K, StableValue<V>> map = StableValue.ofMap(keys, k -> createV(k)); >> >> >> or perhaps even: >> >> >> Map<K, V> map = StableValue.ofMap(keys, k -> createV(k)); > > Yes, consider the 3 capture scenarios: > | API | Capture frequency | Capture Impact | Code Convenience | Flexibility | > |-----|-------------------|----------------|------------------|-------------| > | `StableValue.ofMap(map, k -> ...)` | By accident | single capture is reused > | OK | One generator for all keys | > | `StableValue.computeIfUnset(map, key, k -> ...)` | By accident | capture > happens for all access sites | somewhat ugly | Different generator for > different keys | > | `map.get(k).computeIfUnset(() -> ...)` | Always | capture happens for all > access sites | OK | Different generator for different keys | > > Notice the `ofMap` factory is the most tolerant to faulty captures: even if > it captures, the single capturing lambda is reused for all map stables, > avoiding capture overheads at access sites. Given Java compiler doesn't tell > user anything about captures during compilation, I think `ofMap` is a better > factory to avoid accidentally writing capturing lambdas. I see what you mean. Initially, I thought it would be easy to create memorized functions but it turned out, that was not the case if one wants to retain easy debugability etc. So, I have added a couple of factory methods including this: /** * {@return a new <em>memoized</em> {@linkplain Function } backed by an internal * stable map with the provided {@code inputs} keys where the provided * {@code original} Function will only be invoked at most once per distinct input} * * @param original the original Function to convert to a memoized Function * @param inputs the potential input values to the Function * @param <T> the type of input values * @param <R> the return type of the function */ static <T, R> Function<T, R> ofFunction(Set<? extends T> inputs, Function<? super T, ? extends R> original) { Objects.requireNonNull(inputs); Objects.requireNonNull(original); ... } ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1600035236 PR Review Comment: https://git.openjdk.org/jdk/pull/18794#discussion_r1568671241