Use of super in type parameters

Dan Smith daniel.smith at oracle.com
Wed Apr 17 16:18:32 PDT 2013


On Apr 15, 2013, at 1:37 PM, Martin Buchholz <martinrb at google.com> wrote:

> CompletableFuture currently has a method like this:
> 
>     public CompletableFuture<Void> acceptEither
>         (CompletableFuture<? extends T> other,
>          Consumer<? super T> block) {
>         return doAcceptEither(other, block, null);
>     }
> 
> But that signature is not quite correct (not as general as it could be).  The "correct" signature is
> 
>     public <U super T> CompletableFuture<Void> acceptEither
>         (CompletableFuture<? extends U> other,
>          Consumer<U> block) {
>         return doAcceptEither(other, block, null);
>     }
> 
> but that fails to compile, because type parameters can only be constrained by extends, not super.  Is implementing this on the radar?

My favorite example:
interface Optional<T> {
  <S super T> S get(S alternate);
}
Optional<Integer> o = ...;
Number n = o.get(0.0);

We were _this_ close to adding this, or something like it, with Lambda.  In the end, it didn't make the cut.

The good news is that capture variables already have lower bounds, and inference in Java 8 has been enhanced quite a bit, such that it can mostly handle things like this.  So it seems like it would be a relatively modest task to support the feature someday.

>  Angelika claims
> "lower bounds for type parameters make no sense"
> http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#Why%20is%20there%20no%20lower%20bound%20for%20type%20parameters?
> 
> but I am finding that hard to believe.  Is she right?

Lots of people said a lot of wrong things about generics in the heady Java 5 days.  One or two of those things even ended up in the language spec. :-(  But no, "I can't think of why this would be useful" does not imply "this makes no sense."  (To be fair, I think we all make that leap from time to time.)

> For comparison,  the equivalent static method can be made to do what we want:
> 
>     public static <U> CompletableFuture<Void> acceptEither
>         (CompletableFuture<? extends U> f,
>          CompletableFuture<? extends U> other,
>          Consumer<U> block) {
>         return ...
>     }

Yep, that's the workaround for now.  Or use a weaker signature for your instance method.  (Or both.)

On Apr 17, 2013, at 3:53 PM, Martin Buchholz <martinrb at google.com> wrote:

> With the coming of lambda, it is more likely that people will be creating APIs with "not quite correct" generic types, as we are doing in CompletableFuture.  Which is pretty bad for a feature that is designed specifically to provide compile time safety.

True.  I've made that argument for other axed features as well -- we punt now, and solving the problem later will just be harder, due to further compatibility constraints.  Ultimately, it would be great to make everything perfect out of the gate; but that's not practical.  (And in fact, "out of the gate" in this case was 9 years ago.)  Besides, we have to have something fun to do next time. :-)

—Dan


More information about the lambda-dev mailing list