Bounding generics with 'super' keyword

java generics
bounded type parameters java example
java generic parameter
bounded wildcards in generics in java
java generic method parameter extends
java generics extends a or b
java generics implements
java generics super

Why can I use super only with wildcards and not with type parameters?

For example, in the Collection interface, why is the toArray method not written like this

interface Collection<T>{
    <S super T> S[] toArray(S[] a);
}

Bounded Type Parameters (The Java™ Tutorials > Learning the , Bounded type parameters are key to the implementation of generic algorithms. Consider the following method that counts the number of elements in an array T[]​  Java Generics - Bounded Type Parameters - There may be times when you'll want to restrict the kinds of types that are allowed to be passed to a type parameter. For example, a method that operates on num

As no one has provided a satisfactory answer, the correct answer seems to be "for no good reason".

polygenelubricants provided a good overview of bad things happening with the java array covariance, which is a terrible feature by itself. Consider the following code fragment:

String[] strings = new String[1];
Object[] objects = strings;
objects[0] = 0;

This obviously wrong code compiles without resorting to any "super" construct, so array covariance should not be used as an argument.

Now, here I have a perfectly valid example of code requiring super in the named type parameter:

class Nullable<A> {
    private A value;
    // Does not compile!!
    public <B super A> B withDefault(B defaultValue) {
        return value == null ? defaultValue : value;
    }
}

Potentially supporting some nice usage:

Nullable<Integer> intOrNull = ...;
Integer i = intOrNull.withDefault(8);
Number n = intOrNull.withDefault(3.5);
Object o = intOrNull.withDefault("What's so bad about a String here?");

The latter code fragment does not compile if I remove the B altogether, so B is indeed needed.

Note that the feature I'm trying to implement is easily obtained if I invert the order of type parameter declarations, thus changing the super constraint to extends. However, this is only possible if I rewrite the method as a static one:

// This one actually works and I use it.
public static <B, A extends B> B withDefault(Nullable<A> nullable, B defaultValue) { ... }

The point is that this Java language restriction is indeed restricting some otherwise possible useful features and may require ugly workarounds. I wonder what would happen if we needed withDefault to be virtual.

Now, to correlate with what polygenelubricants said, we use B here not to restrict the type of object passed as defaultValue (see the String used in the example), but rather to restrict the caller expectations about the object we return. As a simple rule, you use extends with the types you demand and super with the types you provide.

Generic Methods and Bounded Type Parameters (The Java , Java Generics - Bounded Type Parameters - There may be times when you'll want to restrict the kinds of types that are allowed to be passed to a type parameter. This is so called self-bounding generics, self-referential generics, or recursive generics, look at the declaration in bracket of the interface, the type B must extends ProviderManagerBuilder which instantiated with B itself. Here is a simplified version interface X < T extends X < T >> It also used in the Enum in java.lang package of the JDK:

The "official" answer to your question can be found in a Sun/Oracle bug report.

BT2:EVALUATION

See

http://lampwww.epfl.ch/~odersky/ftp/local-ti.ps

particularly section 3 and the last paragraph on page 9. Admitting type variables on both sides of subtype constraints can result in a set of type equations with no single best solution; consequently, type inference cannot be done using any of the existing standard algorithms. That is why type variables have only "extends" bounds.

Wildcards, on the other hand, do not have to be inferred, so there is no need for this constraint.

@###.### 2004-05-25

Yes; the key point is that wildcards, even when captured, are only used as inputs of the inference process; nothing with (only) a lower bound needs to be inferred as a result.

@###.### 2004-05-26

I see the problem. But I do not see how it is different from the problems we have with lower bounds on wildcards during inference, e.g.:

List<? super Number> s; boolean b; ... s = b ? s : s;

Currently, we infer List<X> where X extends Object as the type of the conditional expression, meaning that the assignment is illegal.

@###.### 2004-05-26

Sadly, the conversation ends there. The paper to which the (now dead) link used to point is Inferred Type Instantiation for GJ. From glancing at the last page, it boils down to: If lower bounds are admitted, type inference may yield multiple solutions, none of which is principal.

Java Generics - Bounded Type Parameters, super to bound a named type parameter (e.g. <S super T> ) as opposed to a wildcard (e.g. <? super T> ) is ILLEGAL simply because even if it's allowed,  The question mark (?), represents the wildcard, stands for unknown type in generics. There may be times when you'll want to restrict the kinds of types that are allowed to be passed to a type parameter. For example, a method that operates on numbers might only want to accept instances of Number or

Bounding generics with 'super' keyword, Type parameters can be bounded (bounds are explained later in the article); Generic methods can have different type parameters separated by  Bounds. When working with generics, the type parameters often must use traits as bounds to stipulate what functionality a type implements. For example, the following example uses the trait Display to print and so it requires T to be bound by Display; that is, T must implement Display. // Define a function `printer` that takes a generic type `T` which // must implement trait `Display`. fn printer <T: Display> (t: T) { println! ( " {}", t); }

I really like the accepted answer, but I would like to put a slightly different perspective on it.

super is supported in a typed parameter only to allow contravariance capabilities. When it comes to covariance and contravariance it's important to understand that Java only supports use-site variance. Unlike Kotlin or Scala, which allow declaration-site variance. Kotlin documentation explains it very well here. Or if you're more into Scala, here's one for you.

It basically means that in Java, you can not limit the way you're gonna use your class when you declare it in terms of PECS. The class can both consume and produce, and some of its methods can do it at the same time, like toArray([]), by the way.

Now, the reason extends is allowed in classes and methods declarations is because it's more about polymorphism than it is about variance. And polymorphism is an intrinsic part of Java and OOP in general: If a method can accept some supertype, a subtype can always safely be passed to it. And if a method, at declaration site as it's "contract", should return some supertype, it's totally fine if it returns a subtype instead in its implementations

The Basics of Java Generics, Bounded type parameters can be used with methods as well as classes and interfaces. Java  In addition to limiting the types you can use to instantiate a generic type, bounded type parameters allow you to invoke methods defined in the bounds: public class NaturalNumber<T extends Integer> { private T n; public NaturalNumber(T n) { this.n = n; } public boolean isEven() { return n.intValue() % 2 == 0; } //

Java Generics Example Tutorial, http://java9s.com Java Generics Tutorial - Bounded Type Parameters and Multiple Type Duration: 11:30 Posted: Feb 23, 2016 Re: question on bounding generic with Enum 843793 Jun 24, 2004 3:42 AM ( in response to 843793 ) Thanks for the quick response, but I've looked high and low in the bug database, and can't find bug #5067672.

Generics in java # 3, Any Type can be bounded either upper or lower of the class hierarchy in Generics by using bounded wildcards. In short <? extends T> and <? The generics capabilities originally defined in J2SE 1.5 are still with us, but with the advent of Java 8 the corresponding method signatures have gotten far more complex. Most of the functional interfaces added to the language use both generic types and bounded wildcards to enforce type safety.

What is bounded and unbounded wildcards in Generics Java?, What type of wildcard generic types can be used to specify a range for a generic type? Bounding generics with 'super' keyword; However, I still seem to be kind of lost with super keyword: When we declare a collection like that:

Comments
  • Can you explain what you semantically intend to be the difference between <S super T> and <? super T>. Seems to me it's just splitting hairs over syntax.
  • You can't do ? super T[] toArray(? super T[] a), can you?
  • And this is why there is an Object[] toArray() method in the Collection class.
  • so why would <S super T> List<S> addToList(List<S> list, T element){ list.add(element); return list; } not make sense?
  • "it wouldn't do what you'd hoped" - this is just plain wrong. The OP provided a great use case (modulo the dreaded array covariance) with obvious semantics: the collection should be able to fill the array of any more general type and return the said array. There is nothing wrong with it.
  • "since any array of reference type is an Object[], it can therefore be used as an argument to <S super T> S[] toArray(S[] a)" True. However, if S were inferred to be Object, then that would also constrain the return type of the method to Object[], which may cause a compile error depending on the context in which the call is made (if it expects a S[]). So changing the type variable to Object is not a substitute for a super bound.
  • there are some, though few, valid use cases for lower bounds.
  • polygenelubricants: The main point in this answer, that upper type bound are not useful, is incorrect. This is demonstrated in Rotsor's answer. I would like to encourage you to edit this answer to point this out, because in its current form it is misleading people!
  • +1 Your example matches up with a real-world use case in Guava's Optional.or(T). From the documentation: "The signature public T or(T defaultValue) is overly restrictive. However, the ideal signature, public <S super T> S or(S), is not legal Java. As a result, some sensible operations involving subtypes are compile errors".
  • @PaulBellora …and now that Java has its own Optional or the Stream API, it’s biting everyone. The best you can do then, is an actually obsolete .<SuperType>map(t -> t) or .map(Function.<SuperType>identity())
  • @Holger I actually remember this definition and explanation in the guava's doc. I still can't understand why one would want to return a super type; for me it just defeats the purpose, it makes perfect sense to return a subtype, I guess I am missing something here
  • @Eugene this answer’s examples should be explanatory enough; just replace Nullable with Optional and withDefault with orElse. Another example would be CompletableFuture<CharBuffer> f = someIoOperation(); CharSequence result = f.exceptionally(t -> "constant fallback").join();, which would be a reasonable operation, but doesn’t work, unless you insert a workaround like .thenApply(Function.<CharSequence>identity()). Another indirect example would be String.join(", ", () -> Stream.of("foo", "bar").iterator());, which doesn’t work.
  • @Rotsor, can you please explain why the valid variant of method that you proposed in the end of post can be written only as static? I mean this declaration: public static <B, A extends B> B withDefault(Nullable<A> nullable, B defaultValue) { ... }.
  • Underappreciated answer, should be accepted. Lower bounds in method type parameters are useful (as Rotsor showed) and can be implemented (as the author of that paper showed when he did so in Scala). Them being hard to implement sensibly is clearly the real reason they aren't allowed in Java.
  • The accepted answer is wrong. It's correct that this question is about type bounds and not about variance. But lower type bounds using T super R would sometimes be useful, as Rotsors' answer demonstrates, and also the reference to the Guava Optional class.