JDK-6723516 : Confusing generic requirements.
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2008-07-08
  • Updated: 2011-02-16
  • Resolved: 2008-07-22
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_03-b07)
Java HotSpot(TM) Client VM (build 1.5.0_03-b07, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Windows XP SP 2

A DESCRIPTION OF THE PROBLEM :
Perhaps it is documented somewhere by I cannot find it.

Is it possible to get the following to compile without warning

  From the Collections.sort() method
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        Object[] a = list.toArray();
// original
        Arrays.sort(a, (Comparator) c);
// also compile with a warning.
        Arrays.sort(a, (Comparator<? super Object>) c);



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
see previous.

Arrays.sort(a, (Comparator<? super Object>) c);
produces the warning
warning (1,1) [unchecked] unchecked cast
found: java.util.Comparator<capture of ? super T>
required: java.util.Comparator<? super java.lang.Object>


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
If you take the expected type, character for character, then the code should compile without error.


ACTUAL -
I have found  "capture of" means you have to use your imagination as what should fix the problem, and can mean different things in different situations.


ERROR MESSAGES/STACK TRACES THAT OCCUR :
warning (1,1) [unchecked] unchecked cast
found: java.util.Comparator<capture of ? super T>
required: java.util.Comparator<? super java.lang.Object>


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
Another example
Say you write
    public static<K,V> void addResverse(Map<K,V> map1, Map<? extends K, ? extends V> map2) {
        Iterator<Map.Entry<? extends K, ? extends V>> iterator = map2.entrySet().iterator();
    }

The expected type in the warning is
Iterator<Map.Entry<capture of ? extends K, capture of ? extends V>>

however the type actaully expected is
Iterator<? extends Map.Entry<? extends K, ? extends V>>
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Ignore the warning if you cannot make it go away. My IDE has the option of selectively turning off a warning on a line. Perhaps this is why they do this.

Comments
EVALUATION I agree that wildcards are difficult for the mainstream users. This means that, before using wildcards, a programmer should be aware of which advantages and disadvantages might come from their exploitation. In this case I see two examples of bad use of wildcards with the compiler correctly complaining about typing errors which are indeed present in the code. Hopefully I'll manage to show each of them. Example 1) Arrays.sort(a, (Comparator) c); This warning is generated by the compiler because one of the argument in the method call is raw. Becaause of this, the whole signature gets erased and the warning is serving exactly this purpose. Arrays.sort(a, (Comparator<? super Object>) c); The point here is that the warning has changed wrt the former case. This time javac is warning us that a Comparator<? super T> (T is type-variable declared by the sort method) cannot be converted to a Comparator<? super T> in a statically safe way. Let's look at 5.5: "A cast from a type S to a parameterized type (��4.5) T is unchecked unless at least one of the following conditions hold: * S <: T. * All of the type arguments (��4.5.1) of T are unbounded wildcards. * T <: S and S has no subtype X of T , such that the erasures (��4.6) of X and T are the same." In this case S is Comparator<? super T> while T is Comparator<? super Object> the first bullet does not hold, as Comparator<? super T> is not a subtype of Comparator<? super Object> (this assertion can be reduced to the judgment Object <: T by applying JLS 4.10 and 4.5.1.1). The second bullet does not hold either, as we have bounded wildcards as type arguments. The third bullet does not hold. It's true that Comparator<? super Object> is a subtype of Comparator<? super T> (because T is a subtype of Object). However there is at least one subtype of Comparator<? super Object>, namely Comparator<Object> such that the two types have the same the same erasure. This can lead to heap-pollution problems. Example 2 Iterator<Map.Entry<? extends K, ? extends V>> iterator = map2.entrySet().iterator(); The LHS is missing a '?' (as reported by the submitter) that is: Iterator<? extends Map.Entry<? extends K, ? extends V>> iterator = map2.entrySet().iterator(); is the right code. Again, in this case the compiler is simply applying the typing rules described in the JLS. The only thing that could mess up things is that required/found pair in the error message. This is the way in which javac currently reports typing errors, that is, a 'found' type (e.g. String) does not conform to a 'required' type (e.g. Integer). However, the decision as to whether the required part rather than the found part is to be changed is left to the programmer; the 'required' word doesn't mean in any way that the required type is the right one, it depends on the context. For further details about the ongoing work on error message please refer to CR 6492019
22-07-2008