Archive

Archive for October, 2006

CLR Generics – Bibliography

October 23, 2006 1 comment
Categories: .NET Framework

CLR Generics – Comparing with other generics implementations

October 23, 2006 1 comment
Java
Java implements generics by type erasures and full code sharing. This means a few things to us as developers.
Runtime type information is lost.
Only reference types can be used as type parameters for generics.
The plus the java implementation brings in is that the generated bytecode can run on Java 1.4 JVM too. No JVM updates are required. The JVM itself is blind to generics. It is only the compiler which has been updated.
 
C++
In C++ generics are implemented using full code specialization during compiler time. This results in code bloat. Also another problem is that mos of the C++ generics implentations do not offer the strong type checking offered by CLR when it comes to calling methods on generic type parameters.
 
C++ generics offers operator support, which is a painful miss in the CLR implementation.
 
Categories: .NET Framework

CLR Generics – Notable BCL Additions

October 22, 2006 1 comment
System.Collections.Generics is probably the most popular which offer strongly typed generic based collections over their 1.1 counterparts in System.Collections.

Generic based collection Non Generic equivalent
List ArrayList
Dictionary Hashtable
SortedDictionary SortedList
Stack Stack
Queue Queue
LinkedList
IList IList
IDictionary IDictionary
ICollection ICollection
IEnumerable IEnumerable
IEnumerator IEnumerator
IComparable IComparable
IComparer IComparer

System.Nullable introduces nullable value types to CLR. You cannot assign value types like int, long, float, double etc to nulls in 1.1. This would be a pain especially if you are reading a nullable integer field from the database.

Categories: .NET Framework

CLR Generics – Internals

October 22, 2006 1 comment
IL Extensions:
The IL for List<T> looks like:
.class public auto ansi serializable beforefieldinit System.Collections.Generic.List`1<T>
Notice the backtick ‘`’ followed by arity and then followed by type parameters.
The IL for the void Add(T item) looks like:
.method public hidebysig newslot virtual final
    instance void  Add(!T item) cil managed
The _items array of type T is represented as
!0[] class System.Collections.Generic.List`1<!T>::_items
The !0 says this is a place holder and will be replaced with the actual type during code generation by the JIT. 0 is the index of the type paraeter.
 
Traditional generic implementations have followed the following routes to implement Generics.
No Specialization: Possible if every type parameter is represented as a boxed reference type. This will require boing / unboxing still.
Full Specialization: A new copy of code is generated for each specialization. The drawback being the code explosion / increased working set size.
Mixed Code Specialization / Sharing: Share code if type representations are compatible. Else specialize code. Value type representations are considered incompatible whereas reference type representations are considered compatible.
 
CLR takes the mixed mode and Specialization happens during JIT time.
 
Categories: .NET Framework

CLR Generics – Benefits and limitations

October 22, 2006 1 comment
Benefits of using generics

  • Code reuse
  • Compile time type checking
  • Performance benefits by avoiding boxing, unboxing for value types and also type compatibility checks involved with casts are needed for value types as well as reference types

A serious limitation of CLR Generics
Generic type variables cannot use operators. Isn’t it a serious one. A few workarounds http://blogs.msdn.com/ericgu/archive/2003/11/14/52852.aspx
http://www.codeproject.com/csharp/genericnumerics.asp

Categories: .NET Framework

CLR Generics – Other interesting trivia

October 22, 2006 1 comment
Default keyword
Inititalizing a generic to a default is not possible in case of value types. In case of reference types it is as easy as "T myVar=null;". In case of value types this is illegal. For value types the C# language has been extended using a new keyword default. "T myVar = default(T);"

Generic Interfaces, Delegates, Methods: In addition to Generic classes there can be Generic interfaces, Generic delegates and Generic methods. Let us just see an example of each.

public interface IEnumerator : IDisposable, IEnumerator {
	T Current { get; }
}
public delegate void EventHandler (
	object sender, TEventArgs e) where TEventArgs : EventArgs;
public static class Interlocked {
	public static T Exchange( ref T location1, T value) where T : class { ... }
	// Other members and implementation elided for clarity
}

Properties, Indexers, Events, Operators, Constructors, Finalizers cannot have generic type parameters on their own like the Generic method Exchange defined above with a type parameter T.

Categories: .NET Framework

CLR Generics – Constraints

October 22, 2006 1 comment
Generic Constraints
Generic type parameters can be constrained. Assume we want to write an encryption algorithm using a generic type.

public class EncryptionHelper {
...
}

Here we want all the type parameters to inherit from the System.IO.Stream class. How can this be done? Generic type parameters can be constrained. Assume we want to write an encryption algorithm using a generic type.

public class EncryptionHelper {
	public T Encrypt(T stream) {
		stream.Open(); // Error
	}
}

Error object class doesn’t have a Open method. Can this be a solution?

public class EncryptionHelper {
	public T Encrypt(T stream) {
		Stream streamType = (Stream)T; // Error
		...
	}
}

This will work.

public class EncryptionHelper {
	public T Encrypt(T stream) {
		Stream streamType = (Stream)((Object)T); 
		streamType.Open();
		...
	}
}

But what about the type safety which generics promised? The client can pass instance of any class to this method. The actual solution is to use constraints.

public class EncryptionHelper where T:System.IO.Stream {
	public T Encrypt(T stream) {
		stream.Open(); // Error
	}
}

The where clause is used to specify a constraint that the type parameter has to inherit from Stream class. The compiler can check for these calls. This is called a primary constraint. There are two special primary consraints ‘struct’, ‘class’ which specify whether the type argument has to be a value type or reference type. The primary constraint can specify at the most one non sealed type. This type cannot be an enum or a delegate. In addition using a constraint you also specify a zero or more interfaces a type parameter has to comply with. This is called a secondary constraint. In addition to primary and seondary constraints you can specify a type to have a default parameterless constructor. This is called a constructor constraint, specified like "…where T : new() …".

Categories: .NET Framework

CLR Generics – Terminology

October 22, 2006 1 comment
A running example – Pseudo code of the List (List of Tee) class in the System.Collections.Generic namespace of BCL.

[serializable]
public class List :  IList, ICollection, IEnumerable, 
	IList, ICollection, IEnumerable {

	public void Add(T item);
	public T[] ToArray();
	// ... rest of the code elided for clarity
}

// A Client of List
public class Program {
	public static void Main(string[] args) {
		List list = new List();
		list.Add(1);
	}

Terms
Generic Type:
A generic type is a type which has one or more parameters (called type parameters). In the example List is a Generic type because it has one parameter (called type parameter) T.

Generic Type Parameter:
A generic type parameter is a place holder type used by generic types. In the List example above T is the placeholder type. Hence T is the generic type parameter.

Arity:
Arity is the number of type parameters a generic type has. In the List example above the arity of the List type is 1, since T is the one and only type parameter.

public class DictionaryEntry ...

The arity of DictionaryEntry is 2 since it has two type parameters.

Generic Type Argument:
A generic type argument is the type provided by the client while declaration / instantion. In the above example int is the generic type argument.

Constructed Type:
A constructed type is a usage (declaration) of the generic type in which the client has specified at least on of the type parameters as a type argument. A type argument need not be a concrete (non generic / generic type to which all the type parameters are specified – do not confuse this with abstract / concrete used to describe inheritance relationships) type like int as in this example. It can also be a type parameter. We’ll see an example of this in the definition of a open constructed type

Closed Constructed Type:
A closed constructed type is one to which all the type parameters are specified as type arguments using concrete types. In the above example, List is a closed constructed type because it has its only type parameter T specified as a type argument int.

Open Constructed Type:
A Open constructed type is one to which atleast one of the type parameters is specified in terms of another type parameter. This is slightly confusing. Let us see another example here.

public class DictionaryEntry ...

// An dictionary entry which has integer keys
public class IntegerKeyBasedDictionayEntry {
	private inetegerKeyBasedEntry DictionaryEntry;
	...
}

Here only one of the two type parameters specified is concrete, int. The other is specified in terms of the type parameter TValue itself. This is a open constructed type.

Whew so many new terms, well it is needed if you need to understand any article written on generics.

Categories: .NET Framework

CLR Generics – Enter generics

October 22, 2006 1 comment
Generics offer an elegant solution to the problems mentioned here. A generic version of the odd number code written above will be like this.

List list = new List();
1. list.Add(3);
2. list.Add(1);
3. list.Add(5);
list.Sort();
4. int oddNumber = list[0];

The important difference here is that lines labeled 1, 2 and 3 do not result in boxing operations. Line labeled 4 doesn’t require a unbox, cast and type compatibility check.

The reference type example written using the Generic collections in the BCL.

List list = new List();
1. list.Add(aCustomerObject);
2. list.Add(anotherCustomerObject);
...
// This would result in a compile error
3. list.Add(anOrderObject);
...
4. aListControl.DataSource = list
5. aListControl.DataBind();

Line labeled 3 results in a compile time error. This is the type safety offered by the strongly typed generic collections library of the BCL. Its time to introduce some terms in the CLR Generics world. That’ll be in the next entry, till then bye.

Categories: .NET Framework

CLR Generics – Motivation

October 22, 2006 2 comments
A life without generics:
A Value Types example:
ArrayList list = new ArrayList();
1. list.Add(3);
2. list.Add(1);
3. list.Add(5);
list.Sort();
4. int oddNumber = (int)list[0];
The problem with the above code is
lines labeled 1, 2, 3 result in a boxing instruction. Because ArrayList.Add takes an object. Since 3, 1, 5 are integers (read value types) they will be boxed first. Likewise line labeled 4 notice results in an unbox operation because the indexer returns an object. Also cast operation requires a type compatibility check too.

A Reference Types example:

ArrayList list = new ArrayList();
1. list.Add(aCustomerObject);
2. list.Add(anotherCustomerObject);
...
3. list.Add(anOrderObject);
...
// Oops what happens now?
4. aListControl.DataSource = list
5. aListControl.DataBind();
An ArrayList is not a strongly typed collection. What the hell that does mean? An array list can hold objects of multiple types. There is no check offered by the compiler which prevents you from adding an order object to a list in which you intend to store only customer objects. This throws an exception at runtime when the databinding happens. A strongly typed implementation would be caught at compile time (line 3 should give a compile error).

Code duplication:
The only way one could work around this problem in a pre generic world is by writing strongly typed collections deriving from CollectionBase or directly implementing IList. This class has to written one for each type for ex. CustomerCollection, OrderCollection. This is unneccesary code duplication. But you had to live with it if you were to get the benefits of compile time type checking.

Categories: .NET Framework