Should Stream<T> be covariant?

Ali Lahijani alahijani at
Wed Jan 30 12:32:38 PST 2013

As a mental experiment, I tried to create a "constructive proof"
that Stream<T> is covariant in the variable T.
My basic idea is that if it is covariant, it should be possible to elevate
an expression of type Stream<? extends T> to an expression of type
Stream<T> in a suitable "mechanical" fashion. So I tried to implemented a

    public static <T> Stream<T> elevate(Stream<? extends T> delegate)...

To implement the above method, one of course first needs to prove
that Spliterator<T>, Iterator<T> and Optional<T> are covariant in T. But
they are quite straightforward.

    public static <T> Optional<T> elevate(Optional<? extends T> delegate)...
    public static <T> Iterator<T> elevate(Iterator<? extends T> delegate)...
    public static <T> Spliterator<T> elevate(Spliterator<? extends T>

The result of the experiment is pasted below. Almost all methods pass the
test, which, I suppose, means that the Stream API has an exceptionally
clean design.
(It is worth mentioning that not all previous versions of Stream passed the
same test so smoothly.)

But as the compiler will tell you, there is a problem with two methods,
both cases because they use BinaryOperator<T>:

            public T reduce(T identity, BinaryOperator<T> reducer);
            public Optional<T> reduce(BinaryOperator<T> reducer);

BinaryOperator<X> is invariant in X, so passing T to BinaryOperator removes
covariance of Stream. The first method is not needed, it is just a sugar
around the third from of reduce which takes three parameters:

            public T reduce(T identity, BinaryOperator<T> reducer) { return
reduce(identity, reducer, reducer); }

But to be able to emulate the second form, reduce(BinaryOperator<T>), there
should be a method to decompose a Stream as a head/tail pair. Given that
facility, one can emulate reduce(reducer) as tail.reduce(head, reducer,

So here is my question: is it possible that the non-covariant reduce
methods be removed, and a method for head/tail decomposition is added


More information about the lambda-dev mailing list