My general concern is the number of overloads and variants. collect, collectMany and findAll would probably be named something else if created anew today. Adding to this creates confusion IMO. Do you have a Java stream and Groovy as-is version to compare against for each proposed new method? It helps me at least to see what it would take to do the same without the extension.
________________________________ From: Jochen Theodorou <blackd...@gmx.org> Sent: Wednesday, April 9, 2025 6:21 AM To: dev@groovy.apache.org <dev@groovy.apache.org> Subject: [EXT] Re: [DISCUSS] Lazy findAll, collect, collectMany External Email: Use caution with links and attachments. On 09.04.25 03:25, Paul King wrote: > Hi folks, > > [I sent this to grails dev list but meant to send it here and CC them > for feedback - anyway, it is here now, apologies if you see this > twice.] > > I have been looking at the functionality in Groovy-stream[1] and > Gatherers4J[2] lately with a view to filling any gaps in Groovy's > iterator DGM methods. I'm not trying to replicate everything they > contain, just looking for the most useful functionality Groovy might > be missing. > > The biggest missing pieces at this point in my mind are lazy (Iterator > return value) variants of findAll, collect, and collectMany. Groovy's > current variants are eager (return collections and lists). > Groovy-stream gets around this by adding stream-named variants: > filter, map, and flatMap. does Iterator really automatically mean lazy? Is this possible then? def l = [1,2,3] def iterator = l.iterator().findAll{it>1} l[0] = 20 assert iterator.toList() == [20,2,3] The combination of lazy and mutable can be problematic. Also, can I do iterator.toList() multiple times? > One option is to break backwards compatibility (Groovy 5 only). So > only for the versions of those methods which take an Iterator as > input, change the return type to be Iterator. Given how widely used > those methods are, I don't think that is an option for us. well... we could have lazyIt() which return a LazyIterator. that would make things clear. > Actually, findAll currently doesn't have an Iterator variant, so we > could add that but it would still be a behavioral compatibility > breakage since the Object version is used for Iterators and it returns > a list. > > So, we could give up on lazy variants for those methods, but again > given how commonly used they are, that is a pretty big gap. > > So, the other option is to provide alternative names. The best to me seem: > > (A) findAllLazy, collectLazy, collectManyLazy > (B) findAllThen, collectThen, collectManyThen > (C) filter, map, flatMap > (D) something else? (E) lazyIt() I am pretty sure it will not be considered as because it is a bit ugly... but frankly I am no fan of A at all for the very same reason. B I find more nice because it is more semantics based. hmm... what happens if you mix lazy and non-lazy... like for example findAllthen(...).findAll(...) > Option (C) is what Groovy-stream did and would be familiar to Java > Stream users but folks are going to ask, why can't I have that "alias" > for Iterables and arrays, but the intent here is just for the Iterator > variants. I think Lazy best conveys that. Use without "Lazy" for the > eager (think terminal operator) variant and with "Lazy" for the lazy > (think intermediate operator) variant. It also is easier to extend, > the fourth method in terms of gaps is collectEntries, which currently > returns a Map. An Iterator<Map.Entry> return value could be made for > collectEntriesLazy if we wanted. somehow does not really convince me all. > Note that many of our operators are terminal in nature, find, count*, > inject, etc, so this isn't about doing this for all operators > eventually. but findAllThen does not come over as terminal. If they are supposed to, then I don't find the names fitting in the cases of A and B. bye jochen