Archive for 2nd December 2004

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;     }     } 

   } } 

   

 

Aw, dammit…

Argh! One of the drives on my main dev machine just sh*t the brick. Just as I was pondering buying one of those “one-button push” backup systems. Ironically, the drive that died had the /Program Files/ where my backup software lived. So now I’m staring at the machine, trying to figure out what the safest course of action is (thinking that, in situations like this, there is a better-than-normal chance of the system being in some wildly delicate state…)

I got to go to RAID, too.

Plus, I have, like, five deadlines in the next week.