Should Stream<T> be covariant?

Ali Lahijani alahijani at gmail.com
Wed Jan 30 12:36:15 PST 2013


Here is the code:


public class Covariance {

    /**
     * Lemma: {@code Optional<T>} is covariant in {@code T}
     */
    public static <T> Optional<T> elevate(final Optional<? extends T>
delegate) {
        return delegate.isPresent() ? Optional.of(delegate.get()) :
Optional.<T>empty();
    }

    /**
     * Lemma: {@code Iterator<T>} is covariant in {@code T}
     */
    public static <T> Iterator<T> elevate(final Iterator<? extends T>
delegate) {
        return new Iterator<T>() {
            @Override
            public boolean hasNext() {
                return delegate.hasNext();
            }

            @Override
            public T next() {
                return delegate.next();
            }

            @Override
            public void remove() {
                delegate.remove();
            }
        };
    }

    /**
     * Lemma: {@code Spliterator<T>} is covariant in {@code T}
     */
    public static <T> Spliterator<T> elevate(final Spliterator<? extends T>
delegate) {
        return new Spliterator<T>() {

            public int getNaturalSplits() {
                return delegate.getNaturalSplits();
            }

            public Spliterator<T> split() {
                return elevate(delegate.split());
            }

            public Iterator<T> iterator() {
                return elevate(delegate.iterator());
            }

            public boolean isPredictableSplits() {
                return delegate.isPredictableSplits();
            }

            public void forEach(Block<? super T> block) {
                delegate.forEach(block);
            }

            public long getSizeIfKnown() {
                return delegate.getSizeIfKnown();
            }

            public long estimateSize() {
                return delegate.estimateSize();
            }
        };
    }

    /**
     * Theorem: {@code Stream<T>} is covariant in {@code T}
     */
    public static <T> Stream<T> elevate(final Stream<? extends T> delegate)
{
        return new Stream<T>() {
            @Override
            public Stream<T> filter(Predicate<? super T> predicate) {
                return elevate(delegate.filter(predicate));
            }

            @Override
            public <R> Stream<R> map(Function<? super T, ? extends R>
mapper) {
                return delegate.map(mapper);
            }

            @Override
            public IntStream map(ToIntFunction<? super T> mapper) {
                return delegate.map(mapper);
            }

            @Override
            public LongStream map(ToLongFunction<? super T> mapper) {
                return delegate.map(mapper);
            }

            @Override
            public DoubleStream map(ToDoubleFunction<? super T> mapper) {
                return delegate.map(mapper);
            }

            @Override
            public <R> Stream<R> explode(BiConsumer<Downstream<R>, ? super
T> exploder) {
                return delegate.explode(exploder);
            }

            @Override
            public Stream<T> distinct() {
                return elevate(delegate.distinct());
            }

            @Override
            public Stream<T> sorted() {
                return elevate(delegate.sorted());
            }

            @Override
            public Stream<T> sorted(Comparator<? super T> comparator) {
                return elevate(delegate.sorted(comparator));
            }

            @Override
            public void forEach(Consumer<? super T> consumer) {
                delegate.forEach(consumer);
            }

            @Override
            public void forEachUntil(Consumer<? super T> consumer,
BooleanSupplier until) {
                delegate.forEachUntil(consumer, until);
            }

            @Override
            public Stream<T> peek(Consumer<? super T> consumer) {
                return elevate(delegate.peek(consumer));
            }

            @Override
            public Stream<T> limit(long maxSize) {
                return elevate(delegate.limit(maxSize));
            }

            @Override
            public Stream<T> substream(long startingOffset) {
                return elevate(delegate.substream(startingOffset));
            }

            @Override
            public Stream<T> substream(long startingOffset, long
endingOffset) {
                return elevate(delegate.substream(startingOffset,
endingOffset));
            }

            @Override
            protected Object[] toArray() {
                return delegate.toArray();
            }

            @Override
            public <A> A[] toArray(IntFunction<A[]> generator) {
                return delegate.toArray(generator);
            }

            @Override
            public T reduce(T identity, BinaryOperator<T> reducer) {
                /*
                 * TODO this one does work, but the implementation is not
"mechanically generated"
                 */
                // return delegate.reduce(identity, reducer, reducer);

                return delegate.reduce(identity, reducer);
            }

            @Override
            public Optional<T> reduce(BinaryOperator<T> reducer) {
                /*
                 * TODO there is no hope for this one
                 */
                return delegate.reduce(reducer);
            }

            @Override
            public <U> U reduce(U identity, BiFunction<U, ? super T, U>
accumulator, BinaryOperator<U> reducer) {
                return delegate.reduce(identity, accumulator, reducer);
            }

            @Override
            public <R> R collect(Supplier<R> resultFactory, BiConsumer<R, ?
super T> accumulator, BiConsumer<R, R> reducer) {
                return delegate.collect(resultFactory, accumulator,
reducer);
            }

            @Override
            public <R> R collect(Collector<? super T, R> collector) {
                return delegate.collect(collector);
            }

            @Override
            public <R> R collectUnordered(Collector<? super T, R>
collector) {
                return delegate.collectUnordered(collector);
            }

            @Override
            protected Optional<T> max(Comparator<? super T> comparator) {
                return elevate(delegate.max(comparator));
            }

            @Override
            protected Optional<T> min(Comparator<? super T> comparator) {
                return elevate(delegate.min(comparator));
            }

            @Override
            public boolean anyMatch(Predicate<? super T> predicate) {
                return delegate.anyMatch(predicate);
            }

            @Override
            public boolean allMatch(Predicate<? super T> predicate) {
                return delegate.allMatch(predicate);
            }

            @Override
            public boolean noneMatch(Predicate<? super T> predicate) {
                return delegate.noneMatch(predicate);
            }

            @Override
            public Optional<T> findFirst() {
                return elevate(delegate.findFirst());
            }

            @Override
            public Optional<T> findAny() {
                return elevate(delegate.findAny());
            }

            @Override
            public Stream<T> sequential() {
                return elevate(delegate.sequential());
            }

            @Override
            public Stream<T> parallel() {
                return elevate(delegate.parallel());
            }

            @Override
            public Iterator<T> iterator() {
                return elevate(delegate.iterator());
            }

            @Override
            public Spliterator<T> spliterator() {
                return elevate(delegate.spliterator());
            }

            @Override
            public boolean isParallel() {
                return delegate.isParallel();
            }

            @Override
            public int getStreamFlags() {
                return delegate.getStreamFlags();
            }
        };
    }

}


More information about the lambda-dev mailing list