Suppose I have a generic interface Source<T> which is a pure producer of T objects. Being a pure producer is part of the contract of the interface. So it is a reasonable expectation that whatever you can do with a Source<Foo>, should be also possible to do if you have a Source<? extends Foo>.
Now I need to enforce this restriction in the body of Source, so that someone does not accidentally use T in a way that contradicts that contract.
An example from the JDK
As @Miserable.Variable points out, ArrayList<Integer> and ArrayList<? extends Integer> are not equivalent. That's because ArrayList is not covariant as a generic type. Or in other words, ArrayList<T> is not a pure producer of T; specifically, the ArrayList method add(T) consumes a T.
But there are generic types that are pure producers, like Iterator or Iterable. Whatever you can do with an Iterator<Integer> you can also do with an Iterator<? extends Integer>. There is no method like ArrayList.add(T) in Iterator<T>.
I just want to make sure that my interface Source<T> is like Iterator<T> rather than like ArrayList<T>. If someone in the future adds a T-consuming method (like add(T)) to my interface, I want them to get an explicit error.
A more complex example
Simply banning parameters of type T from appearing in the interface is not a full solution. One should also note that T might be used as argument to other generic types. For example, the following method should not be allowed in Source<T>:
public void copyTo(List<T> destination);
because an sneaky subclass may try to read from the list, it is considered a T-consumer; you cannot call this method on a Source<? extends Foo>. On the other hand, this one should be allowed:
public void copyTo(List<? super T> destination);
(There is also another rule that says methods in Source<T> cannot return a List<T>, but can return a List<? extends T>.)
Now, the actual interface can be arbitrarily complex with lots of methods, and the rules are pretty complex themselves. It is very easy to make a mistake. So I want to automate this check.
Is there a unit-testing trick, static analyzer, compiler/IDE plugin, annotation processor (for example with an @Covariant annotation on T), or any other technique or tool that can ensure this for me?
This is not an answer, but too long to fit in a comment.
So it is a reasonable expectation that whatever you can do with a
Source<Foo>, should be also possible to do if you have aSource<? extends Foo>
No, it is not a reasonable expectation. You linked to an entire pdf and it goes to a top level page so it is unclear how you determined this is reasonable, but in general you cannot arbitrarily replace a Foo<T> with a Foo<? extends T>. Foe example, if you have an ArrayList<Integer> a you can call a.Add(Interger.valueOf(5)) but you cannot do that if a is ArrayList<? extends Integer> a.
It is also unclear what are Consumer<T> and sendTo. Is the latter a method in Source<T>>?
Without these clarifications, I am afraid he question is ambiguous.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With