Tiger Generics vs. Whidbey Generics
I know, I know, micro-benchmarks are questionable, besides we are talking about early betas, etc. But I just couldn't resist making some small testing. First of all, a generic list of integers in Whidbey C#:
using System;
using System.Collections.Generic;
namespace LogicStudio.Whidbey.Tests
{
public class GenericValueArrayListTest {
static void Main()
{
DateTime start = DateTime.Now;
List<int> numbers = new List<int>();
for (int i = 0; i < 1000000; i++)
{
numbers.Add(1962);
}
foreach (int i in numbers)
{
int number = i;
}
DateTime finish = DateTime.Now;
System.Console.WriteLine(String.Format("Elapsed time: {0}", finish.Subtract(start)));
}
}
}
Now, it's equivalent in Tiger Java:
package net.logicstudio.tiger.tests;
import java.util.*;
public class GenericValueArrayListTest {
public static void main(String[] args) {
Date start = new Date();
ArrayList<Integer> numbers = new ArrayList<Integer>();
for (int i = 0; i < 1000000; i++) {
numbers.add(1962);
}
for (int i : numbers) {
int number = i;
}
Date finish = new Date();
System.out.printf("Elapsed time: %d ms", finish.getTime() - start.getTime());
}
}
As you can see, I am just creating a million integers list and then accessing every item. C# needed 70-80 milliseconds to complete the job, Java needed 1,430-1,450 milliseconds. Understandable, as Java generics always use reference types so the integers are being boxed/unboxed inside both loops. As I don't expect to see many value collections in real-life situations, the results are not that significative for me, but what about a collection of employees? First the Whidbey C# version:
namespace LogicStudio.Whidbey.Tests
{
public class Employee
{
int id;
string name;
public Employee(int anId, string aName)
{
this.id = anId;
this.name = aName;
}
public int Id
{
get { return this.id; }
}
public string Name
{
get { return this.name; }
set { this.name = value; }
}
}
}
using System;
using System.Collections.Generic;
namespace LogicStudio.Whidbey.Tests
{
public class GenericReferenceArrayListTest {
static void Main()
{
DateTime start = DateTime.Now;
List<Employee> employees = new List<Employee>();
Employee emp = new Employee(101, "Smith, Joan");
for (int i = 0; i < 1000000; i++)
{
employees.Add(emp);
}
foreach (Employee e in employees)
{
Employee currentEmployee = e;
}
DateTime finish = DateTime.Now;
System.Console.WriteLine(String.Format("Elapsed time: {0}", finish.Subtract(start)));
}
}
}
Now the Tiger Java version:
package net.logicstudio.tiger.tests;
public class Employee {
private int id;
private String name;
public Employee(int anId, String aName) {
this.id = anId;
this.name = aName;
}
public int getId() {
return this.id;
}
public String getName() {
return this.name;
}
public void setName(String aName) {
this.name = aName;
}
}
package net.logicstudio.tiger.tests;
import java.util.*;
public class GenericReferenceArrayListTest {
public static void main(String[] args) {
Date start = new Date();
ArrayList<Employee> employees = new ArrayList<Employee>();
Employee emp = new Employee(101, "Smith, Joan");
for (int i = 0; i < 1000000; i++) {
employees.add(emp);
}
for (Employee e : employees) {
Employee currentEmployee = e;
}
Date finish = new Date();
System.out.printf("Elapsed time: %d ms", finish.getTime() - start.getTime());
}
}
This time the C# version took 150 ms and the Java version took 630-650 ms. C# took twice the time with the employees list than with the integers list as a consequence of the compiler use of more efficient representations for value types. Java took less than half the time with the employees list than with the integers list because no boxing/unboxing was needed (Java uses objects in both cases). Anyway and so far, Whidbey is faster than Tiger by a wide margin. In compiling all the examples I used the default switches. Of course, these numbers are totally unscientific so there are no more than a personal divertimento and your results may vary widely.