explode() (original) (raw)

Joe Bowbeer joe.bowbeer at gmail.com
Thu Jan 24 18:05:58 PST 2013


Kevin,

To clarify this for me, how would Arul's sample look with your proposed change?

https://github.com/aruld/java-oneliners/blob/master/src/main/java/com/aruld/oneliners/Item10.java

// Merge tracks from all albums List allTracks = albums.stream() .explode((Downstream downstream, Album element) -> downstream.send(element.tracks)) .collect(Collectors.toList());

--Joe

On Thu, Jan 24, 2013 at 5:36 PM, Kevin Bourrillion <kevinb at google.com>wrote:

On Thu, Jan 24, 2013 at 4:27 PM, Brian Goetz <brian.goetz at oracle.com>wrote:

So, you sort of came full circle to where we started, where we passed a Sink/Block/Consumer representing the downstream. The big complaint against that was "What if I already have a Collection? I have to iterate it myself?"

I'm unwilling to lard Sink/Block/Consumer with these extra methods just to avoid the extra interface; No, my point is that these methods are useful and natural and they belong in Consumer/Whatever, regardless. It's both convenient for the caller, and gives implementors opportunities for greater efficiency. (I don't see how this is full circle unless that exact idea was what was discussed, which it doesn't sound like.) they're not intrinsic enough to Sink/Block/Consumer to be worth the confusion. Though we could have an interface that extends S/B/C that adds the extra methods. I would disagree with such a child interface, because the two are the same thing.

Also, there's something stream-specific to the current Downstream; while the default for send(Stream) just delegates to forEach, this will fail if an element is mapped to an infinite stream. However, a better implementation of send(Stream) could prevent this. I want to leave that door open. Okay, then why not leave that door open for all Consumers, as I propose? So, adding this all up: interface Exploder<T, U> { void explodeInto(T input, FragmentCollector sink); } interface FragmentCollector extends Sink { // or better name // with accept methods for array/stream/Iterable } Stream explode(Exploder<T,U>) Is this any better than the status quo? No, I dislike both. :-) And haven't yet heard any clear argument against my suggestion. I hope to hear others' opinions.

On 1/24/2013 5:43 PM, Kevin Bourrillion wrote: explode() is aptly named for what it did to my brain when I encountered it. :-) A few things are adding up to make it impenetrable. 1. The vast majority of the Stream API, save the obvious exceptions like forEach(), is solidly in the functional style. Collectors aren't really, but as long as I use the prepackaged ones, it /feels/ fairly functional anyway. Now suddenly there's explode, which doesn't feel functional at all. Instead, I need to think of the bit of code I provide to it as an active participant in a pipeline. Things are fed to me, I feed things on down the line. This makes it different, and different is automatically confusing. This can't really be /corrected/, but seems worth nothing; maybe we can account for the difference somehow. 2. In attempting to learn it, I'm confronted with a type, Stream.Downstream, which I won't have heard of before that moment, and whose name reveals little. Is there any particular reason that Sink/Consumer, with its accept(T) method, should not also have "default" methods implementing accept(Collection) and accept(Stream) and accept(T[])? I can't think of any; those sound just plain handy. And if we added those, would there be enough value in preserving Downstream as an identically-signatured type? We could dispense with it, as I've done below. 3. Except sometimes there /is/ value in having a special type even if its signature is identical to another. I suspect that a custom type could help quite a bit in this case: interface Exploder<T,R> { /** * Maps {code input} to zero or more instances of R, sending these * to {@code resultConsumer} to be included in the results of * {@link Stream#explode(Exploder)}. */ void explode(T input, Consumer resultConsumer); }

4. Then there is the name "explode". It's... okay. "unpack"? Nah. It seems maybe 40% possible that a great name is out there eluding us....

-- Kevin Bourrillion | Java Librarian | Google, Inc. |kevinb at google.com <mailto:kevinb at google.com> -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com



More information about the lambda-libs-spec-observers mailing list