IntStreams and the case of the missing reduce

Brent Walker brenthwalker at gmail.com
Tue Jan 7 09:37:56 PST 2014


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