Mentre facevo una piccola ricerca di materiale per un mio prossimo articolo, mi sono imbattuto nel seguente paragrafo che spiega molto bene le differenze di implementazione dei Generics in Java e C#. Esso è tratto da Java Generics - Introduction - Angelika Langer

Translation of Generics

A compiler that must translate a parameterized type or method (in any language) has in principle two choices:

  • Code specialization . The compiler generates a new representation for every instantiation of a parameterized type or method. For instance, the compiler would generate code for a list of integers and additional, different code for a list of strings.
  • Code sharing . The compiler generates code for only one representation of a parameterized type or method and maps all the concrete instantiations of the generic type or method to the one unique representation, performing type checks and type conversions where needed.

Code specialization is the approach that C++ takes for its templates. The C++ compiler generates executable code for every instantiation of a template. The downside of code specialization of generic types is its potential for code bloat.  A list of integers and a list of strings would be represented in the executable code as two implementations of two different types.

This is particularly wasteful in cases where the elements in a collection are references (or pointers), because all references (or pointers) are of the same size and internally have the same representation. There is no need for generation of mostly identical code for a list of references to integers and a list of references to strings.  Both lists could internally be represented by a list of references to any type of object. The compiler just has to add a couple of casts whenever these references are passed in and out of the generic type or method. Since in Java most types are reference types, it deems natural that Java chooses code sharing as its technique for translation of generic types and methods.  [C#, by the way, uses both translation techniques for its generic types: code specialization for the value types and code sharing for the reference types.]

One downside of code sharing is that it creates problems when primitive types are used  as parameters of generic types or methods. Values of primitive type are of different size and require that different code is generated for a list of int and a list of double for instance. It?s not feasible to map both lists onto a single list implementation. There are several solutions to this problem:

  • No primitive types . Primitive types are prohibited as type arguments of parameterized types or methods, that is, the compiler rejects instantiations such as a List .
  • Boxing . Primitive type values are boxed automatically so that internally references to the boxed primitive value were used. (Boxing is the process of wrapping a primitive value into its corresponding reference type, and unboxing is the reverse (see / BOX /.) Naturally, boxing has an negative effect on performance due to the extra box and unbox operations.

Java Generics uses the first approach and restricts instantiation of generics to reference types. Hence a LinkedList is illegal in Java. [In C++ and C# primitive types are allowed as type arguments because these languages use code specialization (in C++ for all instantiations and in C# at least for instantiations on primitive types).]

A me pare un altro punto a favore di C# (vedi boxing/unboxing), ma giudicate voi.


Aggiungi Commento