JDK-6256320 : Change Type Erasure for half defined generics
  • Type: Enhancement
  • Component: specification
  • Sub-Component: language
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2005-04-16
  • Updated: 2011-02-16
  • Resolved: 2006-11-14
Description
A DESCRIPTION OF THE REQUEST :

java.util.Map is defined as: public interface Map<K,V>.

The method I'm interessted in is Set<Map.Entry<K, V>> entrySet();

If I use the Map as legacy Map, type erasure takes place and strips the Map of all generics:
public interface Map{
...
Set entrySet(); }

Although the the entrySet will always return a Set of Map.Entry, I lose this information. It would be more usable and completely transparent to only erase the 'type parameters' of the class K and V.

Which would leave the legacy Map to:
public interface Map{
...
Set<Map.Entry> entrySet();
}

This issue partly related to 5054273. Here is an example of what I mean.

final Map lMap = new HashMap();
final Set<Map.Entry> lEntries = lMap.entrySet();
for(Map.Entry e : lMap.entrySet())
{}

The code lines above will fail at the for loop, because I used the
legacy type map. Type erasure removed the generic definition from
entrySet()

Set<Map.Entry<K, V>> entrySet()

The point is, that although the code fails, we know that entrySet will
always return a Set of Map.Entry, because it is already defined in Map
itself.

What I propose is that type erasure should only remove the generic types
that were not defined and not hardcoded onces. In this case that would
leave the entrySet method:

Set<Map.Entry> entrySet();

That would allow the for loop to compile.

Strangely enough although the for loop above fails, the following code
does not:
class TestTypeErasure <T>
{
    public T get(){return null;}
    public static TestTypeErasure<Boolean> GetBoolean()
    {
        return new TestTypeErasure<Boolean>();
    }
}
final Boolean testTypeErasure = TestTypeErasure.GetBoolean().get();

I think this is kind of inconsistent

JUSTIFICATION :
Set<Map.Entry<K, V>> entrySet():

The Set<Map.Entry> part is hardcoded and does not change regardless of the type paramters or if the Map is used without generics at all.

Furthermore I can not see any compatibilty problems, as the entrySet.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Only strip the not defined type paramters (variable part) but not the hardcoded fixed part during type erasure
ACTUAL -
The information that the Set contains Map.Entry objects is lost.  The following Construct does not compile, although in reality it would never lead to any problems:

final Map lMap = new HashMap();
for(Map.Entry e : lMap.entrySet())
{

}

CUSTOMER SUBMITTED WORKAROUND :
The following is a workaround for the code sample above. Although logical ident, it does compile with an unchecked warning

final Map lMap = new HashMap();
final Set<Map.Entry> lEntries = lMap.entrySet();
for(Map.Entry e : lEntries )
{

}
###@###.### 2005-04-16 07:25:03 GMT

Comments
EVALUATION The request is to modify type erasure so that in the type declaration Foo<T>, erasure only removes T from parameterized types. Then, it so happens that within Map<K,V>'s declaration, Set<Map.Entry<K,V>> erases to Set<Map.Entry>. But if Map<K,V> had a method that took type Map<String,V>, its erasure would just be Map<String>. For type erasure to change the number of type parameters is horrific, especially for compile-time method resolution. We are absolutely not going to accept this request. It is too much to expect to be able to use raw types (Map) while still getting some of the type-safety of generics (Set<Map.Entry>). N.B. This request is much broader than 5054273. 5054273 discussed WHAT members are erased, e.g. inherited methods. This request discusses HOW members are erased.
14-11-2006