Why Stream.concat is a static method - type variable contravariance

Martin Buchholz martinrb at google.com
Thu Oct 11 13:54:30 UTC 2018

Is this the problem discussed here?
(I think I ran into this myself and think the java language should be fixed
to allow "Lower Bound Type Parameters of Methods")

On Wed, Oct 10, 2018 at 9:06 PM, James Roper <james at lightbend.com> wrote:

> With the work I'm doing at the moment at creating a Reactive Streams
> equivalent to java.util.stream, I've often wondered why Stream.concat is a
> static method, rather than an instance method concating the given stream
> onto this. But I think the reason has just dawned on me, and I wanted to
> confirm that I'm correct.
> Java doesn't support contravariant type variables - it does for type
> declarations, but not type variables.
> To put more concretely, if I had a Stream<Integer>, and I wanted to concat
> a Stream<Number>, this is a valid thing to do, the resulting stream would
> be Stream<Number>. But doing that with an instance method would require
> something like this:
> public <S super T> Stream<S> concat(Stream<? extends S> b);
> Which is not supported (specifically, <S super T> type variable declaration
> is not supported). In contrast, what we have in the actual API:
> public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends
> T> b);
> does allow me to concat a Stream<Integer> and Stream<Number> with a
> resulting type of Stream<Number>.
> Is this right, or are there other reasons? Also, is there any possibility
> that Java might support contravariance in type variables in future? My
> reason for wanting it is to provide the following method for reactive
> streams:
> public <S super T> Publisher<S> onErrorResumeWith(Function<? super
> Throwable, ? extends Publisher<? extends S>> f);
> The intent of this method is when a stream encounters an error, the passed
> function is invoked with the error, and that function returns a publisher
> that gets concated to the current stream instead of the error being
> emitted. This could possibly be implemented with a static method:
> public static <T> Publisher<T> onErrorResumeWith(Publisher<? extends T> a,
> Function<? super Throwable, ? extends Publisher<? extends T> f);
> But unlike concat, this method feels and reads much better as an instance
> method, as a static method it's a little confusing.
> Regards,
> James
> --
> *James Roper*
> *Senior Developer, Office of the CTO*
> Lightbend <https://www.lightbend.com/> – Build reactive apps!
> Twitter: @jroper <https://twitter.com/jroper>

More information about the core-libs-dev mailing list