10

I am trying to understand the usage of lower bound wildcards in some depth. I am trying to write a generic method copy which copies the contents of one List to another. I came up with this method signature:

<T> void copy(List<T> dest, List<? extends T> src)

I think this signature is comprehensive to address all scenarios. However, I see that in the Java Collections class the method signature is like this:

<T> void copy(List<? super T> dest, List<? extends T> src)

I do not understand why they use List<? super T> dest instead of just List<T> dest. Is there some extra flexibility with their signature?

River
  • 8,585
  • 14
  • 54
  • 67
user496934
  • 3,822
  • 10
  • 45
  • 64

2 Answers2

6

There is no practical difference without explicit type witnesses.

Without specifying a type witness as done by Eran, there are no differences in flexibility between the two methods.

Essentially, the use of ? super T over T is only a stylistic difference, however it is better practice, as can be seen by applying a number of principles of good code:

  • Explicit intent: ? super T more explicitly shows what types dest should take.
  • Modularity: you don't need to look at the type constraints on src at all to know what types dest can take.
  • Producer Extends, Consumer Super (PECS): a producer parameter ("in" below) should use extends while a consumer parameter ("out" below) should use the super keyword.

Using ? super T is also recommended by the Java tutorials (they even use a copy function):

For purposes of this discussion, it is helpful to think of variables as providing one of two functions:

An "In" Variable
An "in" variable serves up data to the code. Imagine a copy method with two arguments: copy(src, dest). The src argument provides the data to be copied, so it is the "in" parameter.

An "Out" Variable
An "out" variable holds data for use elsewhere. In the copy example, copy(src, dest), the dest argument accepts data, so it is the "out" parameter.

You can use the "in" and "out" principle when deciding whether to use a wildcard and what type of wildcard is appropriate. The following list provides the guidelines to follow:

Wildcard Guidelines:

  • An "in" variable is defined with an upper bounded wildcard, using the extends keyword.
  • An "out" variable is defined with a lower bounded wildcard, using the super keyword.
River
  • 8,585
  • 14
  • 54
  • 67
  • This question was [also answered here](https://stackoverflow.com/questions/34985220/differences-between-copylist-super-t-dest-list-extends-t-src-and-co). I think the example showing all the cases in which they are equivalent is especially convincing. (Can't close as dupe because of bounty.) – River Nov 07 '17 at 19:02
  • @River: It'd probably be better to flag this with a mod flag explaining that it's a dupe instead of answering it. – Makoto Nov 10 '17 at 16:58
  • @Makoto found the duplicate a bit later on – River Nov 10 '17 at 17:11
1

Here's an example:

The following snippet passes compilation with the signature <T> void copy(List<? super T> dest, List<? extends T> src) but doesn't work with the signature <T> void copy(List<T> dest, List<? extends T> src):

YourClass obj = new YourClass ();
List<HashMap<String,String>> lhm = new ArrayList<>();
List<Map<String,String>> lm = new ArrayList<>();
obj.<HashMap<String,String>>copy (lm,lhm);
Eran
  • 387,369
  • 54
  • 702
  • 768
  • The above code snippet passes compilation with both the signatures. Just checked it in Eclipse. – user496934 Oct 29 '17 at 07:27
  • @user496934 Strange. I also tested this on Eclipse, and got `The parameterized method >copy(List>, List extends HashMap>) of type YourClass is not applicable for the arguments (List>, List>)` – Eran Oct 29 '17 at 07:29
  • 1
    @user496934 Did you make the call `obj.>copy (lm,lhm);` or just `obj.copy (lm,lhm);`? – Eran Oct 29 '17 at 07:30
  • My bad, I just made call to obj.copy, Git it now, Thanks. – user496934 Oct 29 '17 at 07:38
  • 1
    It's easy to concoct an example like this, but it's completely unrealistic. I'm still curious what practical use there is. – shmosel Oct 30 '17 at 00:29
  • 3
    But this is just because you are specifying an explicit type witness, which is not the right type witness for one of the cases. That doesn't disprove the claim that the two declarations accept the same possible sets of arguments when not using type witnesses. – newacct Nov 01 '17 at 05:42
  • An explanation would have been helpfull instead of just providing an example. – Wesley De Keirsmaeker Nov 10 '17 at 16:26