It is currently 16 Apr 2024, 17:44
   
Text Size

Generics & 'Type Erasure': disingenuous documentation?

Non-Application Specific Programming Stuff

Moderator: CCGHQ Admins

Generics & 'Type Erasure': disingenuous documentation?

Postby cyberion » 08 Sep 2013, 17:55

Java 5 and onwards allows type variables and parametrized types to be used in declarations. 'Type Erasure' is a grandiose term describing a "process" whereby the compiler eliminates all references to these type variables and parameters in the generated byte code. The reason given is to make Java 5 and onwards compatible with earlier versions of Java, which do not support Generics.

What I suspect is the case is that Generics has been added as incomplete, "design time only" support for parameterized types, which the compiler IGNORES at the point of actual generation of byte code -- hardly what I would call a "process of type erasure". I suspect that the compiler simply does nothing different, and generates the same byte code as the equivalent raw types. The only compiler difference is in its design time validation.

Backward compatibility is a good reason for allowing aliasing of raw types with generic types. It is not a good reason for allowing heap pollution. Heap pollution causes pending runtime exceptions which should be trapped immediately. This suggests that parametrized type information is important at runtime, even when you require backward compatibility.

Can anyone prove me wrong, perhaps by creating a concise example of a generic type that compiles into different byte code from its equivalent raw type?
cyberion
 
Posts: 15
Joined: 08 Sep 2013, 17:48
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby fortion322 » 08 Sep 2013, 18:14

had some time on my hands so ,
No we can't because the compiler doesn't generate any new code at all; Generics is a compile time thingy; even the runtime casts are still present, even if the compiler 'knows' that a generic type is of a matching concrete type. This is caused by the backwards compatibility b.t.w. Hava a look at the following snippet:

Java Code:
import java.util.ArrayList;
import java.util.List;

public class T {
public static void main(String[] args) {
List<String> list= new ArrayList<String>();

list.add("foo");
System.out.println(list.get(0)+"bar");
}

}
The compiler 'knows' that the list will only contain objects of the type String, but still there's a runtime cast:

Java Code:
public class T extends java.lang.Object{
public T();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]);
Code:
0: new #16; //class java/util/ArrayList
3: dup
4: invokespecial #18; //Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: ldc #19; //String foo
11: invokeinterface #21, 2; //InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
16: pop
17: getstatic #27; //Field java/lang/System.out:Ljava/io/PrintStream;
20: new #33; //class java/lang/StringBuilder
23: dup
24: aload_1
25: iconst_0
26: invokeinterface #35, 2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
31: checkcast #39; //class java/lang/String
34: invokestatic #41; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
37: invokespecial #45; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
40: ldc #48; //String bar
42: invokevirtual #50; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
45: invokevirtual #54; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
48: invokevirtual #58; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
51: return

}
See line #31; the cast wouldn't be needed if there were no 'raw' types. The only benefit is type safety during compile time and no explicit casts in the source code.
fortion322
 
Posts: 18
Joined: 05 Sep 2013, 12:58
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby cyberion » 08 Sep 2013, 18:20

thank you very much
The presence of the cast adds weight to the argument that the compiler generates the same code as it does for a raw type. I just don't know why this isn't being stated upfront in documentation, but is being obfuscated in terms like "type erasure" which eventually seem to mean no more than "no change to the byte code generator".

Did you see my point about heap pollution? Backward compatibility is not a reason for this "type erasure". Type is still needed at runtime for throwing exceptions at the correct point.
cyberion
 
Posts: 15
Joined: 08 Sep 2013, 17:48
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby fortion322 » 08 Sep 2013, 18:26

Yep, the generated code is the same as before generics saw the light. Those casts are still needed during runtime because of the 'backward compatibility'. I don't understand your remark on 'heap pollution'; a raw type can store any type of object and only if that cast fails, an Exception will be thrown. The cast can only fail if some 'backward compatible' code goofed ...
fortion322
 
Posts: 18
Joined: 05 Sep 2013, 12:58
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby cyberion » 08 Sep 2013, 18:42

My point about heap pollution is this. If a non-compatible type parameter is used for a generic type through being aliased with a raw type, the runtime allows heap pollution. The runtime will put the rogue object on the heap. It doesn't complain at that point! It should!

It is only if you later assign the object to a "reifiable" type that it can give you a runtime exception.

So, backward compatibility does not mean you should erase type information.

The runtime does not throw an exception on the add method. It defers it until the get.
cyberion
 
Posts: 15
Joined: 08 Sep 2013, 17:48
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby fortion322 » 08 Sep 2013, 18:53

cyberion wrote:My point about heap pollution is this. If a non-compatible type parameter is used for a generic type through being aliased with a raw type, the runtime allows heap pollution. The runtime will put the rogue object on the heap. It doesn't complain at that point! It should!

It is only if you later assign the object to a "reifiable" type that it can give you a runtime exception.

So, backward compatibility does not mean you should erase type information.

The runtime does not throw an exception on the add method. It defers it until the get.
I'm not sure what your issue is. It doesn't surprise me that Java doesn't complain about the add since the List variable, l, is not generic (and the compiler even warns you of this problem). If you made the variable generic, then you'd get a compile-time error from the code above and there wouldn't be any risk of "pollution".
fortion322
 
Posts: 18
Joined: 05 Sep 2013, 12:58
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby fortion322 » 08 Sep 2013, 18:53

that's all just because generics are a compiler issue, nothing on earth forbids anyone to use a List<T> as if it were a raw List (because of the 'backward compatibility' issue). I wish there would've been a compiler flag that forbids those 'raw' types and generates a hard error if a parameterized type were attempted to use as such. You're right, a 'non T' type can be stored in a List<T> without notice, or until it is attempted to use that 'non T' as if it were a T (hence the generated casts).
fortion322
 
Posts: 18
Joined: 05 Sep 2013, 12:58
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby cyberion » 08 Sep 2013, 19:01

fortion322 wrote:that's all just because generics are a compiler issue, nothing on earth forbids anyone to use a List<T> as if it were a raw List (because of the 'backward compatibility' issue). I wish there would've been a compiler flag that forbids those 'raw' types and generates a hard error if a parameterized type were attempted to use as such. You're right, a 'non T' type can be stored in a List<T> without notice, or until it is attempted to use that 'non T' as if it were a T (hence the generated casts).
But generics are not a "compiler issue". They've only implemented it as compiler issue and worded the documentation to make it sound OK.

I do not believe it is correct for the runtime to place something on the heap and then LATER turn round and say, "oh, look what I've found on the heap! That shouldn't be there!"

The reason for this problem is precisely because they have implemented generics as a compiler issue when it is more than that.

This is a usage issue, not a backward compatibility issue. Whenever would your new code want your legacy code to use List<T> in a non-T way?
cyberion
 
Posts: 15
Joined: 08 Sep 2013, 17:48
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby fortion322 » 08 Sep 2013, 19:11

Ok, I reword that phrase: generics are a compile time issue in Java and hence its weakness. OTOH, when you want to go all the way, you end up with possible 'code bloat' as in C++'s templates; I guess the Java language designers wanted to avoid that.
fortion322
 
Posts: 18
Joined: 05 Sep 2013, 12:58
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby fortion322 » 08 Sep 2013, 19:12

cyberion wrote:
fortion322 wrote:that's all just because generics are a compiler issue, nothing on earth forbids anyone to use a List<T> as if it were a raw List (because of the 'backward compatibility' issue). I wish there would've been a compiler flag that forbids those 'raw' types and generates a hard error if a parameterized type were attempted to use as such. You're right, a 'non T' type can be stored in a List<T> without notice, or until it is attempted to use that 'non T' as if it were a T (hence the generated casts).
But generics are not a "compiler issue". They've only implemented it as compiler issue and worded the documentation to make it sound OK.

I do not believe it is correct for the runtime to place something on the heap and then LATER turn round and say, "oh, look what I've found on the heap! That shouldn't be there!"

The reason for this problem is precisely because they have implemented generics as a compiler issue when it is more than that.

This is a usage issue, not a backward compatibility issue. Whenever would your new code want your legacy code to use List<T> in a non-T way?
you're assuming a reasonable user; assumptions are always wrong ;-)
fortion322
 
Posts: 18
Joined: 05 Sep 2013, 12:58
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby cyberion » 08 Sep 2013, 19:16

Then that is what the documentation should say ;-)

It shouldn't obfuscate the "weakness" with excuses about backward compatibility. Backward compatibility does not force type erasure
cyberion
 
Posts: 15
Joined: 08 Sep 2013, 17:48
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby fortion322 » 08 Sep 2013, 19:26

cyberion wrote:Then that is what the documentation should say ;-)

It shouldn't obfuscate the "weakness" with excuses about backward compatibility. Backward compatibility does not force type erasure
I gave it some more thoughts, but, suppose the requirements were:

a) old code should keep on compiling and
b) old code should keep on running and
c) generics are supposed to be a compile time thing only (a consequence of a) and b)?).

then, 'type erasure' is the only solution ... of course that documentation only brags about it.
fortion322
 
Posts: 18
Joined: 05 Sep 2013, 12:58
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby cyberion » 08 Sep 2013, 19:33

fortion322 wrote:
cyberion wrote:Then that is what the documentation should say ;-)

It shouldn't obfuscate the "weakness" with excuses about backward compatibility. Backward compatibility does not force type erasure
I gave it some more thoughts, but, suppose the requirements were:

a) old code should keep on compiling and
b) old code should keep on running and
c) generics are supposed to be a compile time thing only (a consequence of a) and b)?).

then, 'type erasure' is the only solution ... of course that documentation only brags about it.
But c) is not a consequence of a) and b). Nor is type erasure the only solution.

Throwing a runtime exception at the point of heap pollution (which requires runtime generic type information) violates neither a) nor b).

The reason it can't be done is because of type erasure, not backward compatibility!

If I am using a parametrized type, it must be because I intend to access the object in a way that requires it to be of that type. Otherwise there would be no need to constrain it! Calling a legacy function that corrupts the parametrized type is misuse and should be flagged when it happens. Ideally, the error shouldn't be deferred to the point where the object is accessed.

The idea that I could use a parametrized type for one part of its life cycle and then allow it to be something different in the latter part of its life cycle, is not what backward compatibility is supposed to support. Such a thing would be bad practice.
cyberion
 
Posts: 15
Joined: 08 Sep 2013, 17:48
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby fortion322 » 08 Sep 2013, 20:05

cyberion wrote:
But c) is not a consequence of a) and b). Nor is type erasure the only solution.

.
I don't know if it's the only solution, but it is the reasoning that the documentations give:

"Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics."
fortion322
 
Posts: 18
Joined: 05 Sep 2013, 12:58
Has thanked: 0 time
Been thanked: 0 time

Re: Generics & 'Type Erasure': disingenuous documentation?

Postby cyberion » 08 Sep 2013, 20:08

Heap pollution is a result of the implemented solution and not the requirement.

The documentation fails to mention that type erasure is a compromise that is more than just ensuring backward compatibility.

I agree with fortioni that possible compiler and output bloat may be a factor.

I think I was also a little hasty in saying type erasure is a simple matter of ignoring type information at generation time. I now recognise that, once you have decided to employ type erasure, deciding what the equivalent raw type would be is not necessarily a simple matter! With inheritance and correlated parametrization to consider, things could become complex and scenarios could arise that were not there before generics.
cyberion
 
Posts: 15
Joined: 08 Sep 2013, 17:48
Has thanked: 0 time
Been thanked: 0 time

Next

Return to General Programming

Who is online

Users browsing this forum: No registered users and 10 guests


Who is online

In total there are 10 users online :: 0 registered, 0 hidden and 10 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: No registered users and 10 guests

Login Form