<div dir="ltr"><div dir="ltr">On Sat, Apr 20, 2024 at 8:29 PM ІП-24 Олександр Ротань <<a href="mailto:rotan.olexandr@gmail.com">rotan.olexandr@gmail.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto">Gatherers could be effectively terminal, but I don't think Gatherer API designers intended it to be. In related JEP, gatherers are described as a way to declare custom intermediate operations, and introducing "terminal" gatherers would be misleading.</div></blockquote><div>I will show you an API that expands on collectors too. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div dir="auto"><br></div><div dir="auto">Talking about performance, not even considering gather() method itself, creating an instance of Indexed object for each value in stream is costy and might turn into a nightmare for infinite streams.</div></div></blockquote><div>We will have value objects soon (Project Valhalla), by then the object creation will be much more lightweight as it's effectively a tuple. This is not really a thing of concern. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div dir="auto"><br></div><div dir="auto">As for internals of Stream API right now, I am not aware about its current state, so not much to say here except that adding a new type of streams that just slightly extends existing functionality might not be that harmful, I guess.</div><div dir="auto"><br></div><div dir="auto">Regarding API exposure, I don't think that moving it from stream directly to Gatherers factory would be much of a deal since to see index-aware methods user must explicitly convert stream to enumerated.</div></div></blockquote><div>Having another set of EnumeratedStream APIs and implementations is going to be a nightmare to maintain. Also it has bad interpolatability to convert itself back into regular streams for other usages, while Stream<Indexed<T>> are much better in that aspect. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div dir="auto"><br></div><div dir="auto">I also think the I didn't express my point about index consistency clear enough. Consider following:</div></div></blockquote><div>Notice that Stream.filter retains instead of drops the matching elements! Since otherwise your results don't make sense. I will assume you mean "filter" like "dropIf" </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div dir="auto"><br></div><div dir="auto">List.of(1,2,3).stream().enumerated().filter((idx, i) -> i*idx < 2).map((idx, val) -> idx * val)</div><div dir="auto"><br></div><div dir="auto">Result : (4, 9)</div></div></blockquote><div>Does idx start from 0 or 1? All Java indices start from 0, having it start from 1 in enumerated is really weird. I will assume you mean [2, 6]=[1*2, 2*3] </div><div>Your use case is even simpler, this case can be covered in a simple gatherer like this:</div><div>Gatherer.ofSequential(() -> new int[] {0},<br>            Gatherer.Integrator.ofGreedy((counter, v, sink) -><br>                    sink.push(new Indexed<>(counter[0]++, v))))<br></div><div>Better than writing thousands lines of new code. The functionalities are already implemented in my sample project in</div><div><a href="https://github.com/liachmodded/IndexedStream/tree/main/src/main/java/com/github/liachmodded/indexedstream">https://github.com/liachmodded/IndexedStream/tree/main/src/main/java/com/github/liachmodded/indexedstream</a><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div dir="auto"><br></div><div dir="auto">With your approach</div><div dir="auto"><br></div><div dir="auto">List.of(1,2,3).stream().gather(Gatherers.filterIndexed((idx, val) -> idx*val < 2)).gather(Gatherers.mapIndexed((idx, val) -> idx * val))<br></div><div dir="auto"><br></div><div dir="auto">Result : (2, 6)</div></div></blockquote><div>I will assume you mean [0, 3]=[0*2, 1*3] </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div dir="auto"><br></div><div dir="auto">Not only second option is much more verbose, but also indexes of stream are inconsistent between operations.</div></div></blockquote><div>Then what does EnumeratedStream serve? We would assume the enumeration means the enumeration at the current stage so we want the number immediately. If you want the enumeration at a particular stage, it's better to zip your stream items with an index like my gatherer above at an explicit step.</div><div><br></div><div>Also I have already made a showcase git repository with your two test cases at</div><div><a href="https://github.com/liachmodded/IndexedStream/blob/main/src/test/java/com/github/liachmodded/indexedstream/IndexedGatherersTest.java">https://github.com/liachmodded/IndexedStream/blob/main/src/test/java/com/github/liachmodded/indexedstream/IndexedGatherersTest.java</a></div><div>Feel free to rant and tell what you really want that aren't served by these few simple classes.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div dir="auto"><br></div><div dir="auto">PS: regarding findIndex, I did some benchmarking today, you might like to take a look. On average list-based version outperform collector and gatherer-based in more then 10 times. And also lists in stdlib doesn't have any hashcode-based implementations. I wrote 19 implementations in list subclasses and none of them had anything but simple traversing logic inside indexOf. But that's topic of another thread</div></div></blockquote><div>Thanks for the prompt, I will look at it and reply in the other thread.</div></div></div>