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