participate


Generics - Erasure; is it really needed ?
<<   Back to Forum  |   Give us Feedback
This topic has 94 replies on 7 pages.    1 | 2 | 3 | 4 | 5 | 6 | 7 | Next »
Kraythe
Posts:458
Registered: 7/1/03
Erasure; is it really needed ?   
Sep 10, 2003 7:24 AM

 
The way I understand erasure to work is that after the compiler makes the compile time checks of the code and then forgets about the type in the parameterized type. For example:

Set<Integer> values = new Set<Integer>(); 

is interpreted at runtime as:
Set values = new Set(); 


The idea being that the specificity introduced by the bounds is removed at runtime.

I see this idea as very dangerous and generally problematic. We have seen in the forums over the past couple of months many examples of issues that are confronted by implementing generics this way. They make expressions abiguous and also lead to confusion that is not necessary. What is even more critical is that erasure is completely incompatible with dynamic programing and other reflection techniques.

For instance, consider the following code:
public class MyClass {
  public void myMethod(final Set<String> value) {
    // ...
  }
 
  public void myMethod(final Set<Integer> value) {
    // ...
  }
}
 
public void Launcher {
  public final static void main(final String[] args) {
    Class[] paramTypes = Class.forName(args[1]);
    Method myMethod = MyClass.class.getMethod("myMethod", paramTypes);
  }
}


We run the program with ...

C:> java Launcher Set<Integer> 


In this code, which method did I obtain? Since the specificity of the generics is erased after ccompile time, this question would be ambiguous. This is just one of many ambiguities yet to be overcome by generics.

In addition, the given reason for implementing generics using erasure is fraught with logic problems. The proposed reasoning is to preserve backward compatibility so that code compiled with generics will be able to be run on lower version virtual machines. However, the fact is that in order for that to happen, the user would have to replace the rt.jar at the very least; since the 1.5 code could not only be using generics but other features of 1.5 such as the new APIs.

The fact is that developers of efficient and successful projects rarely mix virtual machines in the same project. They do, however, use libraries designed for one virtual machine on another virtual machine. However, almost universally it is the case of a library built on a lower JDK being used on a higher JDK. Only once is a lavender moon, blue moon is too common here, is it the other way around.

To add more fuel to the fire, the developers of the JDK have already decided to break backward compatibility; so why are they keeping backward compatibility in generics when the other code prohibits backward compatibility. Its a paradox.

So what if we dont do erasure? What is the problem with that? The compiler would generate class files that are in addition to the normal class files in a similar manner as it generates invidual classfiles for inner classes. What is the downside? More binary release volume? In return for type safety and the ability to continue to use the most powerful tool in the jdk (reflection)? Sold. Put me down for a dozen.

In the end, I simply cant think of a single reasonable advantage to erasure in the light of already destroyed backward compatibility, increased confusion and crippled dynamic programming.

I implore sun to say, "Uhh ... nevermind that erasure stuff." It will simplify the implementation of generics greatly and simplify the learning curve required for generics. In addition,it will preserve the power of reflection.
 
gafter
Posts:669
Registered: 6/25/98
Re: Erasure; is it really needed ?   
Sep 10, 2003 3:03 PM (reply 1 of 94)  (In reply to original post )

 
In addition, the given reason for implementing
generics using erasure is fraught with logic problems.
The proposed reasoning is to preserve backward
compatibility so that code compiled with generics will
be able to be run on lower version virtual machines.
However, the fact is that in order for that to happen,
the user would have to replace the rt.jar at the very
least; since the 1.5 code could not only be using
generics but other features of 1.5 such as the new
APIs.

The main reason is to allow existing source and class files to interoperate with new source and class files.

To add more fuel to the fire, the developers of the
JDK have already decided to break backward
compatibility; so why are they keeping backward
compatibility in generics when the other code
prohibits backward compatibility. Its a paradox.

We have not broken backward compatibility with the new language and VM changes. Existing source and class files will run in 1.5 without problems.

So what if we dont do erasure? What is the problem
with that? The compiler would generate class files
that are in addition to the normal class files in a
similar manner as it generates invidual classfiles for
inner classes. What is the downside? More binary
release volume? In return for type safety and the
ability to continue to use the most powerful tool in
the jdk (reflection)? Sold. Put me down for a dozen.

The main problem is that all of your existing applications that use generics would require source file changes and then need to be recompiled. Existing sources and binaries would not run properly.

I implore sun to say, "Uhh ... nevermind that erasure
stuff." It will simplify the implementation of
generics greatly and simplify the learning curve
required for generics. In addition,it will preserve
the power of reflection.

We can't simply say nevermind to erasure without a specific implementation strategy to replace it, and you haven't suggested one.
 
gafter
Posts:669
Registered: 6/25/98
Re: Erasure; is it really needed ?   
Sep 10, 2003 3:04 PM (reply 2 of 94)  (In reply to #1 )

 
The main problem is that all of your existing
applications that use generics would require source
file changes and then need to be recompiled. Existing
sources and binaries would not run properly.

I meant your existing applications that use collections.
 
Kraythe
Posts:458
Registered: 7/1/03
Re: Erasure; is it really needed ?   
Sep 10, 2003 4:43 PM (reply 3 of 94)  (In reply to #2 )

 
Why would that be the case? Or are you removing the old style collections from the JDK? I had not heard that woudl be the case.

I cant see any reason that old source could not be recompiled in the new JDK.
 
Kraythe
Posts:458
Registered: 7/1/03
Re: Erasure; is it really needed ?   
Sep 10, 2003 4:45 PM (reply 4 of 94)  (In reply to #3 )

 
By the way, you still havent addressed the bulk of the post in that erasure cripples reflection.
 
brucechapman
Posts:692
Registered: 24/11/98
Re: Erasure; is it really needed ?   
Sep 10, 2003 6:37 PM (reply 5 of 94)  (In reply to #4 )

 
By the way, you still havent addressed the bulk of the
post in that erasure cripples reflection.


The reflection API changes proposed as part of JSR-14, will allow you to rewrite the example in the original post so that it would work with an argument of "List<Integer>", and return the correct method.

So in what specific way(s) does erasure cripple reflection?

Bruce
 
Kraythe
Posts:458
Registered: 7/1/03
Re: Erasure; is it really needed ?   
Sep 11, 2003 3:02 AM (reply 6 of 94)  (In reply to #5 )

 
By the way, you still havent addressed the bulk of
the
post in that erasure cripples reflection.
The reflection API changes proposed as part of JSR-14,
will allow you to rewrite the example in the original
post so that it would work with an argument of
"List<Integer>", and return the correct method.

Ok ..... How? Lets see it.

So in what specific way(s) does erasure cripple
reflection?

It cripples it until you answer how it can be rewritten. Not hypothetically but with a real world example. Rewrite it and tell me how.


 
Kraythe
Posts:458
Registered: 7/1/03
Re: Erasure; is it really needed ?   
Sep 11, 2003 3:33 AM (reply 7 of 94)  (In reply to #1 )

 
In addition, the given reason for implementing
generics using erasure is fraught with logic
problems.
The proposed reasoning is to preserve backward
compatibility so that code compiled with generics
will
be able to be run on lower version virtual
machines.
However, the fact is that in order for that to
happen,
the user would have to replace the rt.jar at the
very
least; since the 1.5 code could not only be using
generics but other features of 1.5 such as the new
APIs.

The main reason is to allow existing source and class
files to interoperate with new source and class
files.

Again, the source files shouldnt be affected unless you intend to completely remove non-generic sets from the JDK. I had not hear that this would be the case. If those collections are still in the JDK then the only code would merely use them like normal. Erasure does nothing to help legacy source files unless I am missing something critical. If I am, please elaborate on exactly what incompatibility would exist without erasure. Lets have some code examples and explanation.

To add more fuel to the fire, the developers of the
JDK have already decided to break backward
compatibility; so why are they keeping backward
compatibility in generics when the other code
prohibits backward compatibility. Its a paradox.

We have not broken backward compatibility with the new
language and VM changes. Existing source and class
files will run in 1.5 without problems.

You misread me. I said that new source files wont compile on older JDKs already. I still see no reason that old source files couldnt compile on the new JDK wihtout erasure. Erasure is a compile time issue, not a runtime issue.

In fact, erasure seems to have no technical grounds whatsoever. I challenge you to prove such grounds because everything I read in the spec and in the forums about the need for erasure simply doesnt wash.

So what if we dont do erasure? What is the problem
with that? The compiler would generate class files
that are in addition to the normal class files in a
similar manner as it generates invidual classfiles
for
inner classes. What is the downside? More binary
release volume? In return for type safety and the
ability to continue to use the most powerful tool
in
the jdk (reflection)? Sold. Put me down for a dozen.


The main problem is that all of your existing
applications that use generics would require source
file changes and then need to be recompiled.

Why would you need source changes? Can you give me an example of an old source file that wont compile under the new JDK without erasure?

Existing
sources and binaries would not run properly.

Again why? The existing binaries would be using the old type-unsafe sets. Why would they not run properly?


I implore sun to say, "Uhh ... nevermind that
erasure
stuff." It will simplify the implementation of
generics greatly and simplify the learning curve
required for generics. In addition,it will preserve
the power of reflection.

We can't simply say nevermind to erasure without a
specific implementation strategy to replace it, and
you haven't suggested one.

Yes I did but perhaps I wasnt clear. Its simple. For every construct like:

  Set<String> strs = new HashSet<String>; 


The compiler generates a utility class (note CLASS files and not source files) that looks like:

public interface Set$$Integer {
  boolean add(Integer o);
  // ... etc
}
 
public class HashSet$$Integer implements Set$$Integer {
  
  boolean add(final Integer o) {
    // .. code
  }
  // ... etc  
 
  UnmodifiableHashSet$$Integer {
    // get methods but no set methods. 
  } 
}


And then the only question is how do you get unmodifiable sets. This can be fixed with an easy change to the jdk.

1) Deprecate collections.unmodifiableSet() and the similar methods.
2) Implement new method in the interface for Collection and Map
public interface Collection {
  // .. other collection methods 
 
  // this is added.
  /**
   * Retrieves an unmodifiable version of the collection. 
   */ 
  public Collection unmodifiable(); 
}


3) implement this method in the legacy sets as well as in the new sets.
4) Implement a typesafe version on the generated collections. ie ...

public interface Set$$Integer {
  boolean add(Integer o);
  
  Set$$Integer unmodifiable();
}


5) Implement this method in the code base for the typesafe sets.
6) Implement methods in the generated set for converting to a non-typesafe set.
7) Compile the generated classes and put them in a special package with a special name like "generics.generated". Let the user give to the compiler an option for what package to put the generated files in as well. (The reason they go into one package is so that if 4 classes use HashSet<String>, we dont want 4 copies of the class in the code.)

There you go. There are some minor details but nothing serious.

What this would accomplish is that it would obviate the need for erasure. Currently there are code generators that do exactly this. It doesnt seem that hard to do. There are some details to be worked out but it would work very well.
 
genepi
Posts:90
Registered: 5/25/00
Re: Erasure; is it really needed ?   
Sep 11, 2003 8:01 AM (reply 8 of 94)  (In reply to original post )

 
Hi,

The way I understand JSR-14, it's a Java language change only (with a particular implementation presented based on generic type erasure). But nothing prevents another company like IBM or Borland to develop a compiler/JVM which keeps the type information in the class file...

In that case, could we have incompatible class files and different program behavior (because reflection would give complete generic type)? Or incompatible API: Sun's one returning the bound type, and other vendors defining a new one that returns the precise generic type?
 
Kraythe
Posts:458
Registered: 7/1/03
Re: Erasure; is it really needed ?   
Sep 11, 2003 8:57 AM (reply 9 of 94)  (In reply to #8 )

 
Hi,

The way I understand JSR-14, it's a Java language
change only (with a particular implementation
presented based on generic type erasure).

Its a language change where sun doesnt want to make the language change. IMHO they dotn want to have to do the work to do it right either in the JVM or by generating classfiles. They are changing the compiler and then borking the rest of the job. My implementation was only one of many ideas. Another idea would be to introduce changes in the VM to accomodate generics.

But nothing
prevents another company like IBM or Borland to
develop a compiler/JVM which keeps the type
information in the class file...

Why would they? With erasure they dotn need to. They merely need to do erasure to support the spec.

Come to think of it, they couldnt because code will be built to depend upon the erasure concept and they would break all that code.

In that case, could we have incompatible class
files and different program behavior (because
reflection would give complete generic type)?

Reflection is totally destroyed by erasure as I demonstrated in the first post. Reflection is the process of examining a class at runtime and using that information to program dynamically. Erasure rips the heart out of reflection.

In the meantime gafter and co are just smiling suavely and saying "dont worry about it ... we will fix it." When people ask how, they cant cough up an answer. This isnt the only thread on the subject.

Or incompatible API: Sun's one returning the bound type,
and other vendors defining a new one that returns the
precise generic type?

Certainly you cant have a JDK that implements one that can run on the other. Look to someone, such as IBM, to take the opportunity to do it right, open source it and bounce Sun right out of the industry. If they do this, Sun deserves it IMHO.

Reflection is the single most powerful tool in the JDK. We dont want promises, assurances and suave remarks. We want concrete answers; ones that will hold up to the rigorous review process.
 
keithgolden
Posts:7
Registered: 6/12/99
Re: Erasure; is it really needed ?   
Sep 11, 2003 6:46 PM (reply 10 of 94)  (In reply to original post )

 
The way I understand erasure to work is that after the
compiler makes the compile time checks of the code and
then forgets about the type in the parameterized type.
For example:
<div class="jive-quote">Set<Integer> values = new Set<Integer>(); </div>
 

is interpreted at runtime as:
<div class="jive-quote">Set values = new Set(); </div>
 


Yes, that's right -- a fact you seem to overlook in your example below.

The idea being that the specificity introduced by the
bounds is removed at runtime.

I see this idea as very dangerous and generally
problematic. We have seen in the forums over the past
couple of months many examples of issues that are
confronted by implementing generics this way. They
make expressions abiguous and also lead to confusion
that is not necessary. What is even more critical is
that erasure is completely incompatible with dynamic
programing and other reflection techniques.

Dynamic programming is a technique for solving optimization problems. Using it to describe a "reflection technique" is a recipe for mass confusion. I do agree with your point that generics don't play nice with reflection. However...

For instance, consider the following code:

<div class="jive-quote">public class MyClass {
  public void myMethod(final Set<String> value) {
    // ...
  }
 
  public void myMethod(final Set<Integer> value) {
    // ...
  }
}</div>



We run the program with ...

No, you don't, because the above code would never compile. As you point out, the compiler erases the types. Since the two myMethods both have the same type signature, the compiler will complain.

In this code, which method did I obtain? Since the
specificity of the generics is erased after ccompile
time, this question would be ambiguous. This is just
one of many ambiguities yet to be overcome by
generics.

Yes, it's an ambiguity, but it's an ambiguity that will be caught by the compiler.

I agree that not being able to access generic parameters in a meaningful way at runtime is somewhat limiting, but until you can actually produce an example that will compile, I remain unconvinced of the danger.
 
brucechapman
Posts:692
Registered: 24/11/98
Re: Erasure; is it really needed ?   
Sep 11, 2003 7:24 PM (reply 11 of 94)  (In reply to #6 )

 
By the way, you still havent addressed the bulk of
the
post in that erasure cripples reflection.
The reflection API changes proposed as part of
JSR-14,
will allow you to rewrite the example in the
original
post so that it would work with an argument of
"List<Integer>", and return the correct method.

Ok ..... How? Lets see it.


It cripples it until you answer how it can be
rewritten. Not hypothetically but with a real world
example. Rewrite it and tell me how.




Using the reflection API javadocs available with the prototype

Caution - untested code !! at least I warned you.


import java.lang.reflect.*;
 
public class MyClass {
  public void myMethod(final Set<String> value) {
    // ...
  }
  public void myMethod(final Set<Integer> value) {
    // ...
  }
}
 
public class /* not void */ Launcher {
  public final static void main(final String[] args) {
    // Class[] /* sic */ paramTypes = Class.forName(args[1]);
    Type paramType = getPtypeOrClass(args[0] /* not 1  !!! */ );
    
    // Method myMethod = MyClass.class.getMethod("myMethod", paramTypes);  
 
    // currently the proposal doesn't have a getMethod() that takes
    // a Type[] - hopefully 1.5 will, but for now scan all methods 
    // looking for the one we want.
    Method[] methods = MyClass.class.getMethods();
    for(int i = 0; i < methods ; i++) {
        if(method[i].getName().equals("myMethod")) {
            Type[] argtypes = method[i].getGenericParameterTypes();
            if(argtypes.length == 1 && paramType.equals(argtypes[0]) {
                // found it 
                System.out.println("found " + method[i]);
                break;
            }
        }
    }
  }
 
   /** converts a String into a Type (Class or ParameterizedType).
   Hopefully 1.5 will have a helper class or something to do this 
   for us, but until then here is a crude implementation. 
   @param s a well formed class name, or generic type with a single 
   type argument (which may itself be a class or generic type with  
   single type argument which itself ... ).
   */
   private Type getPtypeOrClass(String s) {
       int left = s.indexOf("<">");
           assert right > left;
           // assume only a single type parameter to keep this simpler
           String typeParamStr = s.substring(left+1,right);
           assert typeParamStr.indexOf(",") == -1;
           Type parameter = getPtypeOrClass(typeParamStr);
           return new MyParameterizedType(
               Class.forName(s.substring(0,left)),
               parameter
           );
       }
    }
}
 
/** Hopefully 1.5 will include an accessible implementation of 
ParameterizedType, if not - here is a crude one (needs hashCode() at 
least to make it robust.) */
 
class MyParameterizedType implements ParameterizedType {
    private Class base;
    private Type[] args;
    MyParameterizedType(Class base, Type... args) {
        this.base=base;
        this.args=args;
    }
    
    public Type[] getActualTypeArguments() {
        return args;
    } 
 
    public Class getRawClass() {
        return base;
    }
    
 
    public boolean equals(Object o) {
        if(o == null) return false;
        if(! o instanceof ParameterizedType) return false;
        ParameterizedType other = (ParameterizedType)o;
        if(! other.getRawClass().equals(base)) return false;
        type[] otherArgs=other.getActualTypeArguments();
        if(otherArgs.length != args.length) return false;
        for(int i=0; i < args.length; i++) {
            if( ! args[i].equals(otherArgs[i])) return false;
        }
        // phew !!
        return true;
    }
}


I rest my case.

So in what specific way(s) does erasure cripple
reflection?

You still haven't anwered this!

Bruce
 
Kraythe
Posts:458
Registered: 7/1/03
Re: Erasure; is it really needed ?   
Sep 11, 2003 8:41 PM (reply 12 of 94)  (In reply to #11 )

 
Good God!

You replace a single line of code with all of that garbage?

Thanks for proving my point.
 
Kraythe
Posts:458
Registered: 7/1/03
Re: Erasure; is it really needed ?   
Sep 11, 2003 8:44 PM (reply 13 of 94)  (In reply to #10 )

 
No, you don't, because the above code would
never compile. As you point out, the compiler erases
the types. Since the two myMethods both have the same
type signature, the compiler will complain.


Incorrect. The rules for identical method signatures are relaxed for the generics spec. Its on like page 16 or something (not at my computer). The class i indicated compiles fine. Dont believe me? Try it.
 
gafter
Posts:669
Registered: 6/25/98
Re: Erasure; is it really needed ?   
Sep 11, 2003 10:34 PM (reply 14 of 94)  (In reply to #3 )

 
Why would that be the case? Or are you removing the
old style collections from the JDK? I had not heard
that woudl be the case.

I cant see any reason that old source could not be
recompiled in the new JDK.

Well, once you spell out in detail the implementation strategy you have in mind, I will have enough information to answer your question. There are dozens of design choices that would allow one to add generics while retaining the ability to reify type parameters, and all of them sacrifice compatibility in one way or another.
 
This topic has 94 replies on 7 pages.    1 | 2 | 3 | 4 | 5 | 6 | 7 | Next »
Back to Forum
 
Read the Developer Forums Code of Conduct

Click to email this message Email this Topic

Edit this Topic
  
 
 
Forums Statistics

About Sun forums
  • Oracle Forums is a large collection of user generated discussions. It is here to help you ask questions, find answers, and participate in discussions.

    Check out our guide on Getting started with Oracle Forums for a full walkthrough of how to best leverage the benefits of this community.

Powered by Jive Forums