Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't we capture wildcards for the method with two parameters?

Related to that question.

I know about wildcard capturing. For instance, the following could be used for reversing a list:

public static void reverse(List<?> list) { rev(list); } //capturing the wildcard
private static <T> void rev(List<T> list) {
    List<T> tmp = new ArrayList<T>(list);
    for (int i = 0; i < list.size(); i++) {
        list.set(i, tmp.get(list.size()-i-1));
    }
}

Now I'm trying to write the same thing for that kind of situation:

private int compare (Comparable<?> upper, Comparable<?> lower){
    return comp(upper, lower);  //The method comp(Comparable<T>, Comparable<T>) is not applicable for the arguments (Comparable<capture#5-of ?>, Comparable<capture#6-of ?>)
}

private <T> int comp(Comparable<T> upper, Comparable<T> lower){
    return upper.compareTo((T) lower);
}

I expected that it was compiled fine as well. Is it possible to capture wildacrds for methods with two or more parameters that way?

like image 712
user3663882 Avatar asked Jun 08 '15 07:06

user3663882


People also ask

Where can you use a wildcard to denote a parameter type in your code?

In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific).

What is a wildcard parameter?

In the Java programming language, the wildcard ? is a special kind of type argument that controls the type safety of the use of generic (parameterized) types. It can be used in variable declarations and instantiations as well as in method definitions, but not in the definition of a generic type.

What is wildcard capture?

In some cases, the compiler infers the type of a wildcard. For example, a list may be defined as List<?> but, when evaluating an expression, the compiler infers a particular type from the code. This scenario is known as wildcard capture.

Which among the following is valid option for wildcards?

Which of these is wildcard symbol? a) ? b) ! Explanation: In generic code, the question mark (?), called the wildcard, represents an unknown type.


Video Answer


2 Answers

Because, as I said in my answer to your other question, the compiler cannot know that the two ? stand for the same type.

The two ? each stand for some unknown type. The compare method needs two Comparable objects for the same type T. If you call compare from the comp method, the compiler cannot be sure that the two ? stand for the same type.

like image 91
Jesper Avatar answered Oct 13 '22 10:10

Jesper


In this method

private <T> int comp(Comparable<T> upper, Comparable<T> lower){
    return upper.compareTo((T) lower);
}

both of the parameters share the same type-parameter.

Meanwhile, this is not true for the other method:

private int compare (Comparable<?> upper, Comparable<?> lower){
    return comp(upper, lower); 
}

Here, the compiler has no evidence that the type-parameters for upper and lower are the same and that's why refuses to give green light to compilation.

If you want both of the methods to share the same type-parameter(s), you can make the type-parameter class-scoped. For example:

public class YourClass<T> {
     private int comp(Comparable<T> upper, Comparable<T> lower){
         return upper.compareTo((T) lower);
     }

     private int compare (Comparable<T> upper, Comparable<T> lower){
         return comp(upper, lower); 
     }
}

Another option (if you don't like the first one) would be to introduce one and the same upper bound for the type-parameters for comp() and compare(). For example:

private <T extends SomeSuperClass> int comp(Comparable<T> upper, Comparable<T> lower){
    return upper.compareTo((T) lower);
}

private <T extends SomeSuperClass> int compare (Comparable<T> upper, Comparable<T> lower){
    return comp(upper, lower); 
}

Furthermore, if you want to avoid the casting in the comp() method, you can do:

public class YourClass<T extends SomeSuperClass & Comparable<T>> {
     private int comp(T upper, T lower){
         return upper.compareTo(lower);
     }

     private int compare (T upper, T lower){
         return comp(upper, lower); 
     }
}
like image 45
Konstantin Yovkov Avatar answered Oct 13 '22 11:10

Konstantin Yovkov