On Tue, 14 Nov 2023 09:48:13 GMT, Rémi Forax <fo...@openjdk.org> wrote:

>> Viktor Klang has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   Addressing last review feedback
>
> Hello,
> the relation between a stateless gatherer (default initializer) and the 
> default combiner are not obvious to me.
> 
> A default initializer means stateless and a default combiner means 
> sequential, so if i want the integrator of my stateless gatherer to be called 
> in parallel, i need to not use the default combiner but at the same time the 
> combiner I will pass as parameter will not be called because the gatherer is 
> stateless ?
> 
> Having to create a combiner that will be not called seems weird. I'm sure i'm 
> missing something ?

@forax 

> But I found the API surprising, the way to opt-in is to provide a combiner 
> which does not work well with a stateless intermediary operation which by 
> definition does not need a combiner.

"Does not need a combiner" is not strictly true, it's just that the (only) 
combiner which makes sense is `(null,null) -> null` (which is a completely 
valid combiner).

>Why not either using capabilities (like Spliterator and Collector) or 
>subclasses like Greedy, or any other mechanisms instead of the concept of a 
>default initializer/combiner ?

I tried multiple variations of that during the design process, including 
attaching the combiner to the state via `Initializer<T>` (a sealed type whose 
type members were `SequentialInitializer<T>` and `ParallelizableInitializer<T>` 
where the latter had the `combine`-method). This had other problems, such as 
(but not limited to): the latter not being a SAM-type anymore, which led to 
more boilerplate, interactions with composition which were more challenging to 
encode (Sequential andThen Parallelizable, Parallelizable andThen Sequential). 
And it also introduced a bit of slipperly slope to move the goalposts such that 
all the behaviors ended up on a single type, where we'd be back at the original 
formulation, so in the end the current encoding was selected.

>The idea of default initializer/combiner is that those are orthogonal, you can 
>choose the default initializer and the default combiner separatly, but an 
>initializer and a combiner are related, they work together so the idea of 
>default initializer/combiner is leaky. A contrario, there is no such isseu 
>with the default finisher because this one is independant of the others 
>methods of a Gatherer.

I'd say that all of them are related. In the case of forEach and forEachOrdered 
it is the Integrator which wants a certain execution order, so you could argue 
that it is influencing the choice of the combiner. But that is sort of the 
point—they (initializer, integrator, combiner, finisher) are all related in 
important ways, that's why they have a shared home—Gatherer. The reason for 
them being lifted representations (methods that return functions) is to be able 
to more precisely be able to choose, and compose, them—since they should only 
depend on the mutable state which they are passed.

While I think it would have been interesting to a select number of people, 
writing up the pros-cons for each failed experiment would have taken much more 
time to analyze and put into words, the resulting solution proposed in this PR 
was the best of many.

My ambition with this Preview of JEP-461 is to:
1) Verify that the documentation is helpful
2) Verify that the chosen Gatherer encoding is correct
3) Verify that the API surface doesn't have any major foot-guns
4) Verify that the performance of the reference implementation is in the right 
neighbourhood
5) Verify that the chosen, initial, built-in Gatherers are helpful to developers

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

PR Comment: https://git.openjdk.org/jdk/pull/16420#issuecomment-1811953981

Reply via email to