IntStreams and the case of the missing reduce

Zhong Yu zhong.j.yu at gmail.com
Tue Jan 7 09:54:58 PST 2014


Maybe it's ok to introduce a functional type (U, int)->U *local* to
IntStream, specifically to be used in IntStream.reduce().

    interface IntStream
        interface Reducer<U>
            U apply(U, int)

It's less important to primitivize U - one can always use a mutable U
to avoid object creation.

Zhong Yu



On Tue, Jan 7, 2014 at 11:37 AM, Brent Walker <brenthwalker at gmail.com> wrote:
> I guess I am slightly worked up over this because reduce() is so
> fundamental to functional programming and because it comes up so often when
> doing anything really, that I hate to see it curtailed like this.  Also I
> am not a big fun of assymetrys in APIs.
>
> As I said before I appreciate the difficulties and the balancing act you
> had to go through to get lambdas and streams out the door -- I just wish
> you made some different choices here.
>
> In the meantime I am learning to live with these small utility functions so
> it's not all bad (I omit the 3 controversial types...).
>
> Brent
>
> ==================================================
> private static <T, S extends BaseStream<T, S>> void
> checkSequentialStream(final BaseStream<T, S> s) {
>   if (s.isParallel()) {
>     throw new AssertionError("reduce() can only be called on sequential
> streams.");
>   }
> }
>
> public static <U> U reduce(final IntStream s, final U identity, final
> Int2BiFunction<U, U> accumulator) {
>   checkSequentialStream(s);
>   final Ref<U> u = new Ref<>(identity);
>   s.forEach((int x) -> { u.r = accumulator.apply(u.r, x); });
>   return u.r;
> }
>
> public static <U> U reduce(final LongStream s, final U identity, final
> Long2BiFunction<U, U> accumulator) {
>   checkSequentialStream(s);
>   final Ref<U> u = new Ref<>(identity);
>   s.forEach((long x) -> { u.r = accumulator.apply(u.r, x); });
>   return u.r;
> }
>
> public static <U> U reduce(final DoubleStream s, final U identity, final
> Double2BiFunction<U, U> accumulator) {
>   checkSequentialStream(s);
>   final Ref<U> u = new Ref<>(identity);
>   s.forEach((double x) -> { u.r = accumulator.apply(u.r, x); });
>   return u.r;
> }
> ==================================================
>
>
>
> On Tue, Jan 7, 2014 at 7:22 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
>
>> As Richard pointed out, these were all delicate compromises, and I'm sure
>> we didn't make every decision perfectly.  You can argue with the wisdom of
>> any particular compromise, but what you can't do is say "3 types is all we
>> need to add", because you're forgetting the infinite number of *other*
>> people who each have a pet feature that got left out.  We'd have to take
>> the union of all the pet features of all the other people to get to an "all
>> we'd need to do" solution.
>>
>> In other words, we're at a compromise now, and where you're proposing
>> would simply be a *different* compromise.  Which is fine, you can argue the
>> merits of one compromise vs another, and the EG definitely did so at
>> length, but don't fool yourself that there's a "right" answer and a "wrong"
>> answer.
>>
>>
>>
>>
>> On 1/7/2014 9:20 AM, Brent Walker wrote:
>>
>>> As I said in my original email the primitive to primitive we could in my
>>> opinion live without.  It is in the mapping from primitives to the
>>> infinity
>>> of user defined types (the objects domain) that hurts and breaks the
>>> "abstraction" that all streams (primitive and Stream<T>) are created
>>> equal.
>>>   So in total yes 3 types is all we needed to add.  And we would get the
>>> most general version of reduce for the primitive streams -- which by
>>> virtue
>>> of being the most general can implement the other two reduce() methods
>>> that
>>> did make it in.
>>>
>>> Brent
>>>
>>>
>>>
>>> On Tue, Jan 7, 2014 at 2:49 PM, Richard Warburton <
>>> richard.warburton at gmail.com> wrote:
>>>
>>>  Hi,
>>>>
>>>> Yes it would.  And because of one extra type we lost the symmetry between
>>>>
>>>>> the primitive and object streams, and lost the most useful reduce method
>>>>> for raw streams.  I would call that the poorer choice.  The existence of
>>>>> the distinction between primitives and objects in Java is annoying
>>>>> enough
>>>>> as it is -- what's the point of exasperating it by building interfaces
>>>>> with
>>>>> asymmetrys and missing methods for the primitives vs objects.
>>>>>
>>>>>
>>>> I think the thing you need to consider is whenever you say "one more
>>>> functional interface" for primitives its really 3 since you need to cover
>>>> int/long/double. And if you need to specialise by two arguments which
>>>> might
>>>> be different (eg: zip) then its 9 interfaces.
>>>>
>>>> If you look at the API as a whole there are compromises, especially
>>>> around
>>>> primitives. The real solution to the primitive problems is a unified type
>>>> system rather than adding loads more functional interfaces. Hopefully
>>>> this
>>>> will be a focus of development in Java 9.
>>>>
>>>> regards,
>>>>
>>>>    Richard Warburton
>>>>
>>>>    http://insightfullogic.com
>>>>    @RichardWarburto <http://twitter.com/richardwarburto>
>>>>
>>>>
>>>
>


More information about the lambda-dev mailing list