On Sat, Apr 20, 2024 at 8:29 PM ІП-24 Олександр Ротань < rotan.olexa...@gmail.com> wrote:
> 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. > I will show you an API that expands on collectors too. > > 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. > 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. > > 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. > > 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. > 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. > > I also think the I didn't express my point about index consistency clear > enough. Consider following: > 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" > > List.of(1,2,3).stream().enumerated().filter((idx, i) -> i*idx < > 2).map((idx, val) -> idx * val) > > Result : (4, 9) > 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] Your use case is even simpler, this case can be covered in a simple gatherer like this: Gatherer.ofSequential(() -> new int[] {0}, Gatherer.Integrator.ofGreedy((counter, v, sink) -> sink.push(new Indexed<>(counter[0]++, v)))) Better than writing thousands lines of new code. The functionalities are already implemented in my sample project in https://github.com/liachmodded/IndexedStream/tree/main/src/main/java/com/github/liachmodded/indexedstream > > With your approach > > List.of(1,2,3).stream().gather(Gatherers.filterIndexed((idx, val) -> > idx*val < 2)).gather(Gatherers.mapIndexed((idx, val) -> idx * val)) > > Result : (2, 6) > I will assume you mean [0, 3]=[0*2, 1*3] > > Not only second option is much more verbose, but also indexes of stream > are inconsistent between operations. > 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. Also I have already made a showcase git repository with your two test cases at https://github.com/liachmodded/IndexedStream/blob/main/src/test/java/com/github/liachmodded/indexedstream/IndexedGatherersTest.java Feel free to rant and tell what you really want that aren't served by these few simple classes. > > 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 > Thanks for the prompt, I will look at it and reply in the other thread.