Generics: .NET vs. Tiger -- Boxing Penalty Is Very Real

We're not supposed to publish benchmark numbers on beta code, so I'll just urge you to try this one on your own. A colleague of mine, a noted Java author, recently disparaged .NET's generics, saying they were “based on” work done in Java and that Java 1.5's generics and the forthcoming generics in .NET 2.0 were implemented “the same way.” This guy's pretty prominent, so I bothered to look under the hood to confirm some stuff...

The issue is that when a Java 1.5 generic uses a Java “primitive type,“ it boxes and unboxes the type into an object, which is transparent to the programmer but has a significant overhead. .NET 2.0 Generics, on the other hand, does not use Objects when working with “value types“. So .NET generics and Java generics should have different runtime characteristics, based on how much boxing and unboxing goes on. The questions are whether there's a significant difference (yes, if the following is an indicator) and whether there's a practical difference (depends on how often data structures working on value types are used -- experience would suggest “pretty often“).

Like I said, we're not supposed to print benchmarks, but try out these two programs (which were specifically written to highlight an implementation difference between the two platforms):

  Program.cs   #region  Using directives>   using  System;>   using  System.Collections.Generic;>   using  System.Text;>   #endregion   namespace  ConsoleApplication1>  {    class Program> >  {    static void Main(string[] args)>  {   RunIt();    DateTime > start = DateTime >.Now;>   for (int i = 0; i < 5; i++)>  {   RunIt();   }    TimeSpan > elapsed = DateTime >.Now - start;>   Console >.WriteLine("Elapsed time: {0} ms", elapsed);>   Console >.ReadLine();>  }    static void RunIt()>  {    List ><int>[] n = new List ><int>[5];>   for (int i = 0; i < n.Length; i++)>  {   n[i] = new List ><int>();>  }    for (int i = 0; i < 1000000; i++)>  {   n[0].Add(1);   }    for (int i = 1; i < n.Length; i++)>  {    List ><int> newArray = n[i];>   List ><int> oldArray = n[i - 1];>   foreach(int j in oldArray)>  {   newArray.Add(oldArray[j] * 2);   }   }    for (int i = 0; i < n.Length; i++)>  {    List ><int> array = n[i];>   foreach (int j in array)>  {    int number = j;>  }   }   }   }   }       vs.   GenericValueArrayListTest.java   import java.util.*;   public class GenericValueArrayListTest {     public static void main(String[] args) {
     RunIt();
     Date start = new Date();
     for(int i = 0; i < 5; i++){
       RunIt();
     }
     Date finish = new Date();
     System.out.printf("Elapsed time: %d ms", finish.getTime() - start.getTime());
 }   static void RunIt()
 {
     ArrayList<Integer>[] n = new ArrayList[5];       for(int i = 0; i < n.length; i++){
        n[i] = new ArrayList<Integer>();
     }       for (int i = 0; i < 1000000; i++) {
       n[0].add(1);
     }       for(int i = 1; i < n.length; i++){
       ArrayList<Integer> newArray = n[i];
       ArrayList<Integer> oldArray = n[i - 1];
       for(int j : oldArray){
       newArray.add(j * 2);
     }
     }       for (int i = 0; i < n.length; i++) {
  ArrayList<Integer> array = n[i];
      
 for(int j : array){
       int number = j;
     }
     }     }
 }