1

The file GenericInterface.java:

import java.lang.Comparable;
import java.util.function.Function;

public class GenericInterface {
}

interface Comparator<T> {
  int compare(T o1, T o2);

  static <T, U extends Comparable<?>> //comment out this line
  //static <T, U extends Comparable<? super U>> //and uncomment this line to pass compiling
  Comparator<T> Comparing(Function<? super T, ? extends U> mapper) {
    return new Comparator<T>() {
      @Override
      public int compare(T o1, T o2) {
        return mapper.apply(o1).compareTo(mapper.apply(o2));
      }
    };
  }

  //...
}

Then compile it with JDK 1.8 by javac GenericInterface.java -Xdiags:verbose, resulting the following error:

GenericInterface.java:16: error: method compareTo in interface 
Comparable<T#2> cannot be applied to given types;
        return mapper.apply(o1).compareTo(mapper.apply(o2));
                               ^
  required: CAP#1
  found: CAP#2
  reason: argument mismatch; U cannot be converted to CAP#1
  where U,T#1,T#2 are type-variables:
    U extends Comparable<?> declared in method <T#1,U>Comparing(Function<? super T#1,? extends U>)
    T#1 extends Object declared in method <T#1,U>Comparing(Function<? super T#1,? extends U>)
    T#2 extends Object declared in interface Comparable
  where CAP#1,CAP#2 are fresh type-variables:
    CAP#1 extends Object from capture of ?
    CAP#2 extends U from capture of ? extends U
1 error

I can pass compiling by changing this line

static <T, U extends Comparable<?>>

to this

static <T, U extends Comparable<? super U>>

But I don't know why:

CAP#1 extends Object from capture of ?
CAP#2 extends U from capture of ? extends U

Shouldn't CAP#1 and CAP#2 be U extends Comparable<?>? Could anyone tell me how Java captures type variables in a generic method of a generic interface like the one above?

Robert
  • 1,964
  • 1
  • 22
  • 22

1 Answers1

1

Where you have U extends Comparable<?> the compareTo function will be int compareTo(? o). ? is wild so the only valid argument is null.

Conversely, where you have U extends Comparable<? super U> you will have int compareTo(? super U o), which will take any U.

For instance if I was to declare

class Thing extends Comparable<String> {
    int compareTo(String o) { return 0; }
}

then call

Comparator.<Date,Thing>Comparing(myFunc)

We have a problem Thing.compareTo(String) is called with a Thing argument.

(Made up notation, obviously.)

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • Why "? is wild so the only valid argument is null", since "the compareTo function will be int compareTo(? o)"? Why not the valid argument being "Object"? – Robert Apr 23 '17 at 02:08
  • 1
    `?` could be anything. It isn't defined locally. If in the object supplied it were a `String` say (as in my example) and supplied a `Thing` that couldn't be right. – Tom Hawtin - tackline Apr 23 '17 at 04:21