United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6184881 Object.getClass() typing rule could be improved
JDK-6184881 : Object.getClass() typing rule could be improved

Details
Type:
Enhancement
Submit Date:
2004-10-26
Status:
Open
Updated Date:
2014-08-01
Project Name:
JDK
Resolved Date:
Component:
specification
OS:
linux,windows_xp,windows_7
Sub-Component:
language
CPU:
x86
Priority:
P4
Resolution:
Unresolved
Affected Versions:
5.0,6,7
Targeted Versions:

Related Reports
Duplicate:
Duplicate:
Relates:
Relates:
Relates:
Relates:
Relates:

Sub Tasks

Description
A DESCRIPTION OF THE REQUEST :
The jls3 states that for a given t of type T,
t.getClass() is typed Class<? extends erasure(T)>.

I think the getClass() typing rule could be changed to
Class<? extends wildcard(T)>

The wildcard operation is defined by:
if T is parametrized, wildcard(T)=erasure(T)<?>
else                           , wildcard(T)=T
    

JUSTIFICATION :
1) This rule introduce a raw type.
     Raw type must ONLY be used to interact with legacy code.

2) The new Rule introduce a wildcard.
     Relationship between parametrized type and wildcard are based
     on subtyping rules.
     Relationship between parametrized type and wildcard are based
     on raw type conversion.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
the program must not compile
ACTUAL -
the program compile

---------- BEGIN SOURCE ----------
public void f(ArrayList<Integer> l1, ArrayList<String> l2)
   throws InstantiationException, IllegalAccessException {

    l1.getClass().newInstance().addAll(l2.getClass().newInstance());
  }
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
public Class<? extends ArrayList<?>> wildcardGetClass(ArrayList<?> list) {
    return (Class<? extends ArrayList<?>>)list.getClass();
  }
  
  public void f(ArrayList<Integer> l1, ArrayList<String> l2)
     throws InstantiationException, IllegalAccessException {
      wildcardGetClass(l1).newInstance().addAll(
         wildcardGetClass(l2).newInstance());
  }
###@###.### 10/26/04 22:47 GMT

                                    

Comments
EVALUATION

The erasure of ArrayList<Integer> and ArrayList<String> to ArrayList, in Class<? extends ArrayList>, allows the unsound addition of a String in an Integer collection. (Though an unchecked warning is raised by javac.)

The proposal means that getClass() would return a Class<? extends ArrayList<?>> object, which is incompatible with other Class<? extends ArrayList<?>> objects. This is compatible with existing code like:
  List<String> l = ...
  Class<? extends List> c = l.getClass();
because the new type of the RHS, Class<? extends List<?>>, is a subtype of Class<? extends List>.

Note that the proposed return type:
  Class<? extends wildcard(T)>, where wildcard(T)=erasure(T)<?> if T is parameterized...
is not rich enough, because the type of
  new Foo<Integer,String>.getClass()
becomes
  Class<? extends Foo<?>>
whereas the "right" answer is
  Class<? extends Foo<?,?>>
The correct definition is wildcard(T<A1..An>)=T<?,..,?> (i.e. n wildcards)

A disadvantage of enriching Class's type argument is that it will break idiomatic use of Class.cast. Today, you can write:
  List<Integer> x = ...;
  Class<? extends List> cl = x.getClass();
  List<Integer> y = cl.cast(null);
and get a warning at cast(), because of the unchecked conversion from List to List<Integer>. But with the proposal, the analogous code doesn't compile:
  List<Integer> x = ...;
  Class<? extends List<?>> cl = x.getClass();
  List<Integer> y = cl.cast(null);
because List<?> returned by cast() cannot be converted to List<Integer>. The only way to avoid the error is to cast cl.cast(..) up to List and suffer the unchecked conversion warning to List<Integer>. This is effectively what getClass() does already.

Overall, the proposal seems like a good idea, but it has moderate complexity and a fairly small payoff.
                                     
2006-10-31



Hardware and Software, Engineered to Work Together