Should Stream<T> be covariant?

Ali Lahijani alahijani at gmail.com
Wed Jan 30 14:23:13 PST 2013


On Thu, Jan 31, 2013 at 1:14 AM, Ali Lahijani <alahijani at gmail.com> wrote:

> On Thu, Jan 31, 2013 at 12:25 AM, Brian Goetz <brian.goetz at oracle.com>wrote:
>
>> Of course it is possible to remove the invariant BinaryOperator -- it
>> could be replaced with
>>
>>   BiFunction<? super T, ? super T, ? extends T>
>>
>> Clearly that would be less convenient in some cases, and would have some
>> cost in API readability, since everyone knows what a BinaryOperator is but
>> one has to read more carefully to figure out what the BiFunction is
>> supposed to do.
>>
>> So I'll turn your question around to you: what benefits would we get from
>> doing so, that would make it worth suffering the consequences of the above?
>>
>
> To be able to do a reduce even when what you have is a mere Stream<?
> extends T>, not a full Stream<T>.
>
> Currently there is no type-safe way to do a seedless reduce like this:
>
> Stream<? extends CharSequence> stream = ...
> Optional<CharSequence> total = stream.reduce((s1, s2) -> s1.toString() +
> s2.toString());
>
> I suspect even BiFunction<? super T, ? super T, ? extends T> wouldn't
> solve that.
>


I also kind of hoped, when that elevate() method can be implemented, it
could be added as an static method in Stream.
That way Stream<? extends T> and Stream<T> would be truly interchangeable.
Sort of declaration-site covariance for free.

I mean one direction is already there: Stream<? extends T> is assignable
from Stream<T>. The other direction, from Stream<? extends T> to Stream<T>
can be added as a library method, if Stream becomes fully covariant.

Streams aside, I think adding static methods to Iterator, Spliterator,
Iterable, etc. which do the same kind of elevation might be useful as well.


Best


More information about the lambda-dev mailing list