flatMap

Brian Goetz brian.goetz at oracle.com
Mon Dec 17 19:18:08 PST 2012


So, of the names suggested here so far for flatMap, my favorite is the 
one inspired by Don -- mapMulti.  It still sounds like map, is pretty 
clear what it's about (multi-valued map), and it steers clear of a lot 
of other pitfalls.

While the bikeshed paint is still wet, we can talk about the API. 
Here's an improved proposal.  This may not be perfect, but it's 
definitely better than what we have now.

interface DownstreamContext<T> /* placeholder name */ {
     void yield(T element);
     void yield(T[] array);
     void yield(Collection<T> collection);
     void yield(Stream<T> stream);
     // can add more
}

interface Multimapper<T,U> /* placeholder name */ {
     void map(DownstreamContext<U> downstream, T element);
}

interface Stream<T> {
     ...
     <U> Stream<U> mapMulti(Multimapper<T,U> mapper);
     ...
}


This handles the "generator" case that the current API is built around, 
but also handles the other cases well too:

Example 1 -- collection.

   foos.mapMulti((downstream, foo)
                  -> downstream.yield(getBars(foo)))...

Example 2 -- generator.

   ints.mapMulti((d, i) -> { for (int j=0; j<i; j++)
                                 d.yield(j);
                           })

Example 3 -- stream.

   kids.mapMulti(
         (d, k) -> d.yield(adults.stream().filter(a -> isParent(a, f))));


The downstream context argument is still annoying, but I think is 
clearer than the current "sink" argument is.  The alternative would be 
to have N special-purpose functional interfaces and N overloads for the 
non-generator cases (stream, collection) in addition to the current 
generator form.



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