Getting compile error after extending Generic to Comparable<Generic> - java

class A<T extends Comparable<? super T>> {
Supplier<T> supp;
A(Supplier<T> supp) {
this.supp = supp;
}
static <T extends Comparable<? super T>> A<T> of(Supplier<T> supp) {
return new A<T>(supplier);
}
<U> A<U> map(Function<? super T, ? extends U> mapper) {
return A.of(() -> mapper.apply(this.supp.get()));
}
}
When I compile, I get error saying:
type argument U is not within bounds of type-variable T
where U,T are type-variables:
U extends Object declared in method <U>map(Function<? super T,? extends U>)
T extends Comparable<? super T> declared in class A
I feel that I need to make U in mapper extend something, but I am not really sure how, I have tried U extends Comparable, etc. but they don't work.

Related

Java: misunderstanding generics and wildcards

Consider the following code:
public final class Algorithm {
public static <T extends Comparable<? super T>>
T max(List<? extends T> list, int begin, int end)
{
// ...
}
}
Is the List<? extends T> list parameter declaration equal to List<? extends Comparable<? super T>> list?
There is a very slight difference.
List<? extends T> means
a List of objects of an unknown type that is either T or a subclsss of T
List<? extends Comparable<? super T>> means
a List of objects of an unknown type that is either Comparable<? super T> or an implementation of Comparable<? super T>.
Let's consider this class hierarchy: A and B are unrelated classes that both implement Comparable<A> and are both final. Yes, I know this situation is contrived.
If, from the return value, T is inferred to be A, you can only pass a List<A> to a parameter of type List<? extends T>. However, you can pass a List<A>, as well a List<B> to a parameter of type List<? extends Comparable<? super T>>.
Here is an example demonstrating my point:
public static void main(String[] args) {
List<A> aList = Collections.singletonList(new A());
List<B> bList = Collections.singletonList(new B());
A a = f(aList);
A b = f(bList); // doesn't compile
A c = g(bList);
A d = g(bList);
}
public static <T extends Comparable<? super T>> T f(List<? extends T> list) {
return null;
}
public static <T extends Comparable<? super T>> T g(List<? extends Comparable<? super T>> list) {
return null;
}
final class A implements Comparable<A> {
#Override
public int compareTo(A o) {
return 0;
}
}
final class B implements Comparable<A> {
#Override
public int compareTo(A o) {
return 0;
}
}
In reality though, very rarely do things like class B implements Comparable<A> happen, so for the most part, the two types in question are the same.

How does Java capture type variables in a generic method of a generic interface?

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?
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.)

Why does Function.identity() break type reification but t -> t does not?

Answers found at Java 8 lambdas, Function.identity() or t->t seem to imply that Function.identity() is almost always equivalent to t -> t. However, in the testcase seen below, replacing t -> t by Function.identity() results in a compiler error. Why is that?
public class Testcase {
public static <T, A, R, K, V> Collector<T, A, R> comparatorOrdering(
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper,
Comparator<? super K> keyComparator,
Comparator<? super V> valueComparator) {
return null;
}
public static void main(String[] args) {
Map<Integer, String> case1 = Stream.of(1, 2, 3).
collect(comparatorOrdering(t -> t, t -> String.valueOf(t),
Comparator.naturalOrder(), Comparator.naturalOrder()));
Map<Integer, String> case2 = Stream.of(1, 2, 3).
collect(comparatorOrdering(Function.identity(), t -> String.valueOf(t),
Comparator.naturalOrder(), Comparator.naturalOrder()));
}
}
Case 1 compiles just fine but case 2 fails with:
method comparatorOrdering in class Testcase cannot be applied to given types;
collect(comparatorOrdering(Function.identity(), t -> String.valueOf(t),
required: Function<? super T#1,? extends K>,Function<? super T#1,? extends V>,Comparator<? super K>,Comparator<? super V>
found: Function<Object,Object>,(t)->Strin[...]Of(t),Comparator<T#2>,Comparator<T#3>
reason: inferred type does not conform to upper bound(s)
inferred: Object
upper bound(s): Comparable<? super T#4>,T#4,Object
where T#1,A,R,K,V,T#2,T#3,T#4 are type-variables:
T#1 extends Object declared in method <T#1,A,R,K,V>comparatorOrdering(Function<? super T#1,? extends K>,Function<? super T#1,? extends V>,Comparator<? super K>,Comparator<? super V>)
A extends Object declared in method <T#1,A,R,K,V>comparatorOrdering(Function<? super T#1,? extends K>,Function<? super T#1,? extends V>,Comparator<? super K>,Comparator<? super V>)
R extends Object declared in method <T#1,A,R,K,V>comparatorOrdering(Function<? super T#1,? extends K>,Function<? super T#1,? extends V>,Comparator<? super K>,Comparator<? super V>)
K extends Object declared in method <T#1,A,R,K,V>comparatorOrdering(Function<? super T#1,? extends K>,Function<? super T#1,? extends V>,Comparator<? super K>,Comparator<? super V>)
V extends Object declared in method <T#1,A,R,K,V>comparatorOrdering(Function<? super T#1,? extends K>,Function<? super T#1,? extends V>,Comparator<? super K>,Comparator<? super V>)
T#2 extends Comparable<? super T#2>
T#3 extends Comparable<? super T#3>
T#4 extends Comparable<? super T#4> declared in method <T#4>naturalOrder()
My environment is Windows 10, 64-bit, Oracle JDK build 1.8.0_92-b14.
UPDATE: Seeing as this compiles under ecj, I have a follow-up question: Is this a bug in javac? What does the JLS have to say about this case?
Ecj is able to infere the correct(?) type argument (Integer) to match the constraints. Javac for some reason comes to a different result.
Thats not the first time javac/ecj behave differently in inference of type parameters.
In that case you can give javac a hint with Function.<Integer>identity() to make it compileable with javac.
For the difference between Function.identity() and t->t:
Function.identity() is Function<T,T>
t->t in that case is Function<? super Integer, ? extends Integer>
So t->t is more flexible in the methods it can match to.
The difference between i -> i and Function.identity() is apparent in situation where (1) collectors are nested and (2) upcast is needed somewhere in deep level of nesting.
Example: Suppose we are to classify elements in List<Object> into map with particular lists by element class. (It resembles Guava ClassToInstanceMap except the value is List, so something like hypothetical ClassToInstanceMultimap.) The downstream collector toList() normally collects values into List<Object>. However, if the value type of map is wildcard type List<?>, type inference cannot simply match it. The solution is to adapt collector to pretend it collects List<?>, which is done by intermediate collectingAndThen collector.
The point is now, what should the finisher function look like? Lambda i -> i behaves like Function<List<Object>, List<?>>, which allows upcast. Function.identity() with fixed input and output type T gives no room for upcast we need, hence code won't compile.
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
public static void main(String[] args) {
class Apple {}
class Pear {}
List<Object> list = List.of(new Apple(), new Pear(), new Apple());
Map<Class<?>, List<Object>> obj;
obj = list.stream().collect(groupingBy(Object::getClass, toList())); // compiles
Map<Class<?>, List<?>> wild;
wild = list.stream().collect(groupingBy(Object::getClass, toList())); // wont compile
wild = list.stream().collect(groupingBy(Object::getClass, collectingAndThen(toList(), i -> i))); // compiles
wild = list.stream().collect(groupingBy(Object::getClass, collectingAndThen(toList(), identity()))); // wont compile
wild = list.stream().collect(groupingBy(Object::getClass, collectingAndThen(toList(), (List<Object> i) -> (List<?>)i))); // compiles
System.out.println(wild);
}

Implement an interface that extends comparable

So I have an interface Foo is constructed like:
public interface Foo<T extends Comparable<? super T>>
and I'm trying to implement Foo in my class bar like:
public class Bar<T> implements Foo<T>
but I get getting the error type argument T#1 is not within bounds of type-variable T#2
but when I try to implement Foo as:
public class Bar<T> implements Foo<T extends Comparable<? super T>>
I get > expected and <identifier> expected
Your syntax is a bit off. Try moving the bounds to the declaration of T as in this:
public class Bar<T extends Comparable<? super T>> implements Foo<T> {
...
}

declaring Iterator<? extends E & Comparable<? super E>> iterator in java

Can I declare the following in Java?
public class NewIterator<E extends Comparable<? super E>> implements Iterator<E> {
NewIterator(Iterator<? extends E & Comparable<? super E>> iterator){
...
}
I am getting an error saying
Multiple markers at this line
- Incorrect number of arguments for type Iterator<E>; it cannot be parameterized with arguments <? extends E, Comparable<? super E>>
- Syntax error on token ",", ; expected
- Syntax error on token "&", , expected
- Syntax error on token ")", ; expected
By defining your class as
class NewIterator<E extends Comparable<? super E>> implements Iterator<E> {
you say that E has to implement Comparable<? super E>.
Now in the constructor you try to repeat that and allow subtypes of E.
NewIterator(Iterator<? extends E & Comparable<? super E>> iterator){
...
}
If you do just
public NewIterator(Iterator<? extends E> iterator) {
}
You should get what you want because E already defines that it's a type that implements the comparable interface.
Example
class IntegerNumber {}
class PositiveNumber extends IntegerNumber implements Comparable<IntegerNumber> {}
class OddPositiveNumber extends PositiveNumber {}
private NewIterator<PositiveNumber> newIterator;
void foo() {
Iterator<PositiveNumber> iterator = createIteratorFrom(
new PositiveNumber(1),
new OddPositiveNumber(7)
);
this.newIterator = new NewIterator(iterator);
}
If you use PositiveNumber in NewIterator<E extends Comparable<? super E>> you can replace E by PositiveNumber. So your constructor accepts Iterator<? extends PositiveNumber>. You can now create an iterator over any subclass of PositiveNumber but since that class inherits from PositiveNumber it must also inherit the Comparable<IntegerNumber> interface.

Categories

Resources