Hi Anthony,

Thanks for your suggestion of using a Stream.Builder instead of a Consumer. 
However, one of the goals for mapMulti is not to create an additional Stream. 
Also, I fear that using a builder, but throwing an exception on a call to 
build, is counter-intuitive and perhaps confusing to the user.

Kind regards,

Patrick

> On 25 Jun 2020, at 18:12, Anthony Vanelverdinghe <d...@anthonyv.be> wrote:
> 
> Hi
> 
> Given the signature of flatMap is:
> <R> Stream<R> flatMap​(Function<? super T, ? extends Stream<? extends R>> 
> mapper)
> 
> I'd like to propose the following signature for the new method:
> <R> Stream<R> builderMap(BiConsumer<? super T, ? super Stream.Builder<R>> 
> mapper)
> 
> This way both methods are named "...Map", and the name "builderMap" follows 
> naturally from the argument's type.
> If the given mapper invokes Stream.Builder::build, an IllegalStateException 
> should be thrown.
> 
> Kind regards,
> Anthony
> 
> On 25/06/2020 02:58, Paul Sandoz wrote:
>> Hi,
>> 
>> We traded CPS style for reusing existing functional interfaces. Originally 
>> the signature (my first choice) was as you indicate.
>> 
>> By chance it just so happens that the current signature is the same shape as 
>> that for the accumulating argument type of the three arg collect terminal 
>> operation:
>> 
>> Stream
>> <R> R collect(Supplier<R> supplier,
>>               BiConsumer<R, ? super T> accumulator,
>>               BiConsumer<R, R> combiner);
>> 
>> IntStream
>> <R> R collect(Supplier<R> supplier,
>>               ObjIntConsumer<R> accumulator,
>>               BiConsumer<R, R> combiner);
>> 
>> Same for the accumulator of a Collector too.
>> 
>> However, I suspect you would argue these terminal accumulation cases are 
>> different from the intermediate case, as we are not accumulating but passing 
>> or accepting (loosely returning) zero or more elements that replace the 
>> input element.
>> 
>> It’s my hope that generic specialization will allow the primitive stream 
>> types to fade into the background, along with the primitive functional 
>> interfaces. In that respect the addition of three functional interfaces for 
>> use on the primitive stream types is not so terrible.
>> 
>> 
>> Regarding the name, you should have seen the first one :-) it was terrible.
>> 
>> Here’s my few brush strokes on the bike shed. I wonder what people think of 
>> mapAccept. The specification talks about accepting elements, because that is 
>> the operative method name on Consumer. So we can say "T is replaced with the 
>> elements accepted by the Consumer<R>", or “ The Consumer<R> accepts the 
>> elements that replace T"
>> 
>> Paul.
>> 
>> 
>> 
>>> On Jun 24, 2020, at 1:01 PM, John Rose <john.r.r...@oracle.com> wrote:
>>> 
>>> I like this new API point a lot; it allows flexible, local, temporary
>>> control inversion in the context of one stream transform.
>>> 
>>> What’s the performance model?  It seems like the SpinedBuffer
>>> implementation makes a worst-case assumption about the number
>>> of pending values, that there will be many instead of zero or one.
>>> 
>>> But I guess the pipeline stuff already works in terms of pushes, so
>>> the good news might be that this is really just a drill-down from the
>>> user API into the kinds of operations (push-flavored) that go on
>>> most of the time.
>>> 
>>> OK, so I like the function but I have a beef with its bike shed
>>> color.  First of all, this is a control-inversion (CPS) pattern,
>>> which is very powerful but also notoriously hard to read.
>>> I think that in Java APIs, at least in Stream APIs, code is
>>> easier to read if the logical data flow is from left to right.
>>> 
>>> (This is a language-specific observation.  Apart from varargs,
>>> Java method APIs read favorably when extra control arguments
>>> are added onto the end of the argument list.  Also, the convention
>>> for generic functional interfaces is that the return value type
>>> goes to the right, e.g., R in Function<A,R>.)
>>> 
>>> So the BiConsumer is backwards, because the logical return
>>> should be written, if not as a true return (which would appear
>>> at the end of type parameter lists), at the end of the incoming
>>> parameters (and in the last type parameter).
>>> 
>>> I also think “multi” is needlessly “learned” sounding.  A simple
>>> spatial preposition would work well: mapThrough, mapAcross, etc.
>>> I think I prefer mapAcross because the term “across” can be read
>>> adverbially: “we are mapping T across to Consumer<R>”.
>>> 
>>> So:
>>> 
>>> mapAcross(BiConsumer<? super T, Consumer<R>> mapper)
>>> mapAcrossToInt(BiConsumer<? super T, IntConsumer> mapper)
>>> mapAcross​(IntObjConsumer<IntConsumer> mapper)
>>> 
>>> This does require additional FI’s like IntObjConsumer, but
>>> I think that is a negligible cost.  Making the control inversion
>>> *readable* is the high order bit here, not minimizing the number
>>> of trivial FIs.
>>> 
>>> (I almost hear David Bowman, in his space suit, saying, “My API…
>>> It’s full of bikesheds!”  There’s a meme for that.)
>>> 
>>> — John
>>> 
>>> On Jun 24, 2020, at 3:57 AM, Patrick Concannon 
>>> <patrick.concan...@oracle.com> wrote:
>>>> Hi,
>>>> 
>>>> Could someone please review myself and Julia's RFE and CSR for JDK-8238286 
>>>> - 'Add new flatMap stream operation that is more amenable to pushing’?
>>>> 
>>>> This proposal is to add a new flatMap-like operation:
>>>> 
>>>> `<R> Stream<R> mapMulti(BiConsumer<Consumer<R>, ? super T> mapper)`
>>>> 
>>>> to the java.util.Stream class. This operation is more receptive to the 
>>>> pushing or yielding of values than the current implementation that 
>>>> internally assembles values (if any) into one or more streams. This 
>>>> addition includes the primitive variations of the operation i.e. 
>>>> mapMultiToInt, IntStream mapMulti, etc.
>>>> 
>>>> issue: https://bugs.openjdk.java.net/browse/JDK-8238286 
>>>> <https://bugs.openjdk.java.net/browse/JDK-8238286>
>>>> csr: https://bugs.openjdk.java.net/browse/JDK-8248166 
>>>> <https://bugs.openjdk.java.net/browse/JDK-8248166>
>>>> 
>>>> webrev: http://cr.openjdk.java.net/~pconcannon/8238286/webrevs/webrev.00/ 
>>>> <http://cr.openjdk.java.net/~pconcannon/8238286/webrevs/webrev.00/>
>>>> specdiff: 
>>>> http://cr.openjdk.java.net/~pconcannon/8238286/specdiff/specout.00/overview-summary.html
>>>>   
>>>> <http://cr.openjdk.java.net/~pconcannon/8238286/specdiff/specout.00/overview-summary.html>
>>>> 
>>>> 
>>>> Kind regards,
>>>> Patrick & Julia

Reply via email to