5

I have read often that Java wildcards are a concept that is more powerful than the concept of use-site variance. But in my understanding, the concept of Java wildcards is exactly equal to the concept of use-site variance.

So what is the difference between the two? Can you give a concrete example that is possible with Java wildcards but not with use site variance?

For example, the first answer in How does Java's use-site variance compare to C#'s declaration site variance? is one example where the claim of my question is made:

First off, if I remember correctly use-site variance is strictly more powerful than declaration-site variance (although at the cost of concision), or at least Java's wildcards are (which are actually more powerful than use-site variance).

However, the answer does not state what is the difference, only that there is one.

Edit: A first difference I have found here (first paragraph on Page 112) seems to be that use-site variance completely disallows calling a method that has a type parameter in the wrong position while wildcards allow calling it with some types. E.g., you cannot call add, on a List<? extends String>. With Java wildcards, you can call add on such a class, but you have to use null as argument.For contravariance, one can call any method that returns a contravariant parameter but one has to assume that the return type is Object. But is this the only difference?

Community
  • 1
  • 1
gexicide
  • 38,535
  • 21
  • 92
  • 152
  • Is this different than this question? http://stackoverflow.com/questions/4231305/how-does-javas-use-site-variance-compare-to-cs-declaration-site-variance – Isaiah van der Elst Jul 17 '14 at 15:24
  • 1
    @IsaiahvanderElst: No, the question you linked is about declaration site variance (e.g., C#'s `out`) vs. use site variance. My question is about use site variance vs. wildcards which seem to be exactly the same for me. But the first answer in the question you linked at least states my claim: "or at least Java's wildcards are (which are actually more powerful than use-site variance)" – gexicide Jul 17 '14 at 15:25
  • @IsaiahvanderElst: I phrased the first sentence of my previous comment incorrectly. What I wanted to say was "**Yes**, this question is totally different from the one you linked." Hope it got clear in the explanation. – gexicide Jul 17 '14 at 15:35
  • @gexicide: It looks like there is a mistake in the example answer given. The person probably meant that: `...or at least Java's wildcards are (which are actually more powerful than declare-site variance).`. Java provides use-site variance annotations through wildcards so I can not see how one should be better than the other. – jilt3d Jul 17 '14 at 15:38
  • @jilt3d: I don't think so! This is not the first time I have read that Java generics are *more* than usual use-site variance. In addition, the parenthesis would be a total duplicate then, since the author already mentions that use-site variance is more powerful than decl-site variance in the same sentence. – gexicide Jul 17 '14 at 15:41
  • @gexicide: Yes, it could be a duplicate just to emphasize this fact. Can you provide us more resources/examples/links, please? – jilt3d Jul 17 '14 at 15:42
  • Does the concept of use-site variance allow for a completely unknown type? For example List>... Or is the concept covering just the List extends T> and List super T> cases? – Isaiah van der Elst Jul 17 '14 at 15:45
  • 1
    @IsaiahvanderElst: I do think it does. This is called *bivariance*. However, in any language that has an `Object` type which is the root of the type hierarchy, bivariance is equal to `covariance` with `Object`. This is also true with wildcards since `?` is equal to `? extends Object`. – gexicide Jul 17 '14 at 15:49
  • @jilt3d: Here, for example, is an interesting article: http://www.jot.fm/issues/issue_2004_12/article5.pdf. See the first sentence on page 112: "Unlike wildcards, use-site variance relies heavily on read-only and write-only semantics." – gexicide Jul 17 '14 at 16:06

1 Answers1

6

After reading a lot on this topic, I seem to have found an answer in this paper of Altidor, Reichenbach, and Smaragdakis. The main addition that Java generics have in contrast to use-site variance is capture conversion which allows capturing the previously unknown type of a wildcard in a type parameter. This example from the paper explains it best:

One complication is that Java wildcards are not merely use-site variance, but also include mechanisms inspired by existential typing mechanisms. Wildcard capture is the process of passing an unknown type, hidden by a wildcard, as a type parameter in a method invocation. Consider the following method, which swaps the order the two elements at the top of a stack.

  <E> void swapLastTwo(Stack<E> stack) { 
        E elem1 = stack.pop();
        E elem2 = stack.pop();
        stack.push(elem2); 
        stack.push(elem1); 
   }

Although a programmer may want to pass an object of type Stack<?> as a value argument to the swapLastTwo method, the type parameter to pass for E cannot be manually specified because the type hidden by ? cannot be named by the programmer. However, passing a Stack<?> type checks because Java allows the compiler to automatically generate a name for the unknown type (capture conversion) and use this name in a method invocation.

I.e., in Java, we can call swapLastTwo() using a Stack<?> as input argument. The compiler then captures the ? into a the type variable E and therefore knows that we can call push on the elements we just poped. With use-site variance, we could not do this as the type system would lose the information that the element returned from pop is of the type that push anticipates.

Note that we have to use a type parameter to capture the type. Not doing so will make the type checker treat the type returned from pop differently as the type that push anticipates.

E.g., this does not compile in Java:

Stack<?> s = ...;
s.push(s.pop());

Here, the type of the element of s will be captured into two different fresh type variables (called capture 1 of ? and capture 2 of ? in eclipse. The type checker treats these type variables as different and the code does not compile. By using a generic method we can capture the type of ? into a named parameter that allows calling push and pop.

I am not sure if this is the only difference between Java wildcards and "usual" (whatever that is) use-site variance, but at least it seems to be a very notable difference.

gexicide
  • 38,535
  • 21
  • 92
  • 152