Why Can't I Use a Type Argument in a Type Parameter with Multiple Bounds

Why can't I use a type argument in a type parameter with multiple bounds?

I'm also not sure why the restriction is there. You could try sending a friendly e-mail to the designers of Java 5 Generics (chiefly Gilad Bracha and Neal Gafter).

My guess is that they wanted to support only an absolute minimum of intersection types (which is what multiple bounds essentially are), to make the language no more complex than needed. An intersection cannot be used as a type annotation; a programmer can only express an intersection when it appears as the upper bound of a type variable.

And why was this case even supported? The answer is that multiple bounds allow you to control the erasure, which allows to maintain binary compatibility when generifying existing classes. As explained in section 17.4 of the book by Naftalin and Wadler, a max method would logically have the following signature:

public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll)

However, this erases to:

public static Comparable max(Collection coll)

Which does not match the historical signature of max, and causes old clients to break.
With multiple bounds, only the left-most bound is considered for the erasure, so if max is given the following signature:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

Then the erasure of its signature becomes:

public static Object max(Collection coll)

Which is equal to the signature of max before Generics.

It seems plausible that the Java designers only cared about this simple case and restricted other (more advanced) uses of intersection types because they were just unsure of the complexity that it might bring. So the reason for this design decision does not need to be a possible safety problem (as the question suggests).

More discussion on intersection types and restrictions of generics in an upcoming OOPSLA paper.

Java generics: Multiple bounds with type parameter

Section 4.4 of the Java language spec seems to explicitly disallow this. A Type Bound is specified as:

TypeBound:
extends TypeVariable
extends ClassOrInterfaceType {AdditionalBound}

AdditionalBound:
& InterfaceType

So it looks like you can specify a Type Variable ("T"), or you can have a list of classes and interfaces, but you can't mix them.

https://docs.oracle.com/javase/specs/jls/se18/html/jls-4.html#jls-4.4

Can't resolve 'Type argument is not within bounds of type-variable' error

Change this line

public class MinPriorityQueue<T extends Comparable<T>>

to this:

public class MinPriorityQueue<T extends Comparable<? super T>>

The issue here is that T extends ShortestPathVertex<E> in method Dijkstra, so T needs not implement Comparable directly. But this was necessary in your version of MinPriorityQueue. My change fixes this problem.

Explanation: In MinPriorityQueue<T> Q = ... T is a subtype of ShortestPathVertex<E> which implements Comparable<ShortestPathVertex<E>>. This means T is comparable to values of type ShortestPathVertex<E> (which is a super type of T). But in your version of MinPriorityQueue you define that T must be comparable to the same type T. If you also want to accept super type, you must define it by <? super T>.

You can try (just for demonstration): In method Dijkstra substitute every occurence of T by ShortestPathVertex<E>. This works also with the simpler definition of class MinPriorityQueue.

Another example for using super in this way: Look at the method Collections.binarySearch in the Java Class Library.

Bound mismatch error on generics type argument for a generic class that extends another generic class

That error occurs because you have no compile time guarantee that T is an instance of Foo. You have only the runtime guarantee that Foo is assignable from T, which the compiler does not care about. You can literally make this compile without warnings by suppressing them:

@SuppressWarnings({ "unchecked", "rawtypes" })
private static <T> ObjectManager<T> createFooManager(Class<T> type) {
if(Foo.class.isAssignableFrom(type))
return new FooManager(type); //Error: Bound mismatch
return new ObjectManager<T>(type);
}

That is probably not the answer you were looking for, but I don't think you can get rid of the warnings without suppressing them. What I would infer from the inevitability of those warnings is that the initial approach is incorrect. Why is it that you need to pass in a class as parameter? If the class parameter is known at compile time, you could simply call different methods for different classes. If the class is not known at compile time, you should never be in a position to benefit from that generic parameter at all.

Generics; Type argument is not within its bounds

B's type has to be a subtype of Y as you defined it B<T : Y>, but neither X nor Z is a subtype of Y. X is a supertype of Y, and Z has no vertical connection to Y at all.

Even if they were subtypes, you couldn't do what you were hoping to. Since your class has a T var, T has to be invariant for it to work. Invariant means you cannot implicitly up- and down-cast the type of an instance of the class.

Consider how it would break if it allowed you to:

val bY: B<Y> = B<Y>()
val bX: B<X> = bY // not allowed because of invariance

// If it were allowed:
bX.one = X()
val y: Y = bY.one // ClassCastException: cannot cast X to Y

Type parameter cannot have any other bounds if it's bounded by another type parameter: what does this mean and how to resolve it?

For the meaning of the error, see this question:

Why can't type parameter in Kotlin have any other bounds if it's bounded by another type parameter?

But if your custom list contains elements of type T and you want to compare them, then T should implement Comparable<T>.

So this should be all you need:

class MyList<T: Comparable<T>> {
fun insertSorted(ele: T) {
}
}


Related Topics



Leave a reply



Submit