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

Reply via email to