The Problem with .NET Generics

One of the most awaited features of Microsoft .NET 2.0 is generics. Generics promise to increase type safety, improve performance, reduce code duplication and eliminate unnessecary casts. The most obvious application of generics in the framework class library are the generic collections in the new System.Collections.Generic namespace. Much has been written about those, but they are not the topic of this article.

Generics and arithmetics

The purpose of this article is to examine what generics have to offer for creating generic arithmetic types. As it turns out, not much.

Why this is important

One of the main applications of templates in C++ is to write generic arithmetic types. Surprisingly enough, doing this is not possible with .NET generics. Some people might think that generic arithmetic types are a fringe application, but everytime you draw a line using System.Drawing you use types such as Point and PointF that could benefit from a generic implementation. Another area where generic arithmetic types are important is the very large field of numerical programming, including mundane types such as vectors and matrices as well as more esoteric types like complex numbers and quaternions.

The Problem

Let us for example try to write a generic class to represent a point on a 2D surface. This is a very common data structure that is used for drawing and storing shape data. See for example the Point and PointF structures in the System.Drawing namespace, which could be implemented as a single type using generics.
(The samples in this article are written in C#, but the same problem exists for all .NET languages including VB.NET)

struct Point<T> {
	T x,y;
	public Point<T>(T x,T y) {
		this.x=x;
		this.y=y;
	}
	public static T operator +(T a,T b) {
		return new Point(a.x+b.x,a.y+b.y);
	}
	...
}

This structure could then be used like this:

Point<int> p1; //a point with integer coordinates, like System.Drawing.Point
Point<float> p2; //a point with single precision floating point coordinates, like System.Drawing.PointF
Point<double> p3; //a point with double precision floating point coordinates.

Something like this would work in C++, since it does not put any constraints on type parameters. But in .NET type parameters without any constraints are assumed to be of the System.Object type, so there is not much you can do with them.

Obviously there should be some way to constrain the type paramter T so that T has a + operator, like static T operator +(T a, T b). But (presumably in the interest of simplicity), there exists no way to constrain type parameters by requiring the existence of certain operators or methods. The only way to constrain type parameters is by requiring the type to inherit a base class or to implement an interface. (There is one special case of a method constraint, the new() constraint which requires the existence of a parameterless constructor. But this is useless in this case.)

Interface constraints are a bit limited because interfaces can not contain static methods or operators. The canonical example for an interface constraint is the IComparable<T> interface constraint that is used in the System.Collections.Generic namespace whenever a type has to be constrained to have an order (for example in the SortedList<T> class). You can only use the generic version of SortedList for types that implement the IComparable<T> interface. This makes sense since if you do not have an order, you can not sort. Fortunately all the basic data types such as System.Int32 (int) and System.Double (double) implement this interface.

A similar interface should exist for types that support certain arithmetic operations. An interface for types that support all basic arithmetic operations might look like this:

interface IArithmetic<T> {
	T Add(T a);
	T Subtract(T a);
	T Multiply(T a);
	T Divide(T a);
}

Since there are some types like System.String that support addition but none of the other basic arithmetic operations, it might be a good idea to make this more granular by providing separate interfaces for the basic arithmetic operations.

interface IAddable<T> {
	T Add(T a);
}
...
interface IArithmetic<T>: 
	IAddable<T>,
	ISubtractable<T>,
	IMultipliable<T>,
	IDivisible<T> 
{}

The problem is that the basic data types such as System.Int32 (int) and System.Double (double) do not implement such an interface, even though they support all the required arithmetic operations.

The net result is that something like the above-mentioned generic point class can not be designed to use the basic data types, which of course makes it totally useless. There exist various kludges to work around the issue. For example it would be possible to wrap the basic data types to make them support the required interface. But this requires a lot of additional code and results in unacceptably low performance.

Is there a solution?

Going back to C++ templates

First of all, there is one solution that I definitely do not want. To abolish type constraints and make .NET generics more similar to C++ templates. C++ templates are a compile-time feature much like a macro preprocessor and are thus not a good solution for a highly dynamic language such as C#.

IArithmetic<T>

The simplest practical solution would be to let the basic data types inherit an interface for arithmetic operations similar to the IComparable<T> interface. This would be a very small and unobtrusive change and offer great benefits for writing generic arithmetic types in C# and other .NET languages. No compiler or runtime changes would be nessecary. It is totally incomprehensible to me why microsoft has not done this.

Method Constraints

A more radical approach would be to support method constraints instead of just interface constraints. This would be quite complicated since you would have to specify the exact signature of the method you require. For example in the point class it is not sufficient to require that a class/struct has a + operator. You also have to specify what type the arguments and return value have. So the syntax would look somewhat like this:

struct Point<T> 
	where T: 
		T operator + (T,T),
		T operator - (T,T)
{ ... }

This is obviously much too complicated for a language like C# that strives to be simpler than C++. Method constraints would also require compiler and runtime changes, so the chances of something like this being implemented are quite low.

Implicit interface constraints

Another approach that has some of the benefits of method constraints without the arcane syntax would be implicit interface constraints. You would specify which methods you require in an interface, but classes would not have to implement this interface. They would just have to contain all the required methods with the right signatures.

struct Point<T>
	where T: implicit IArithmetic<T>
{ ... }

Here any T would be allowed that has the required methods Add, Subtract, Multiply, Divide with the right signatures. T would not have to explicitly implement the IArithmetic<T> interface, hence the name implicit interface inheritance.

This approach would IMHO be the most flexible one, but it would probably lead to a religious debate between the advocates of static and dynamic typing. It would also require changes to the compiler, so this is not likely to happen anytime soon.

The notion of an implicit interface has come up on several discussions about this topic. See for example
this discussion.
I hacked a small utility class that emits automatic wrapper classes called AutoCaster. Integrating something like this into the compiler should not be too hard, so wether to support implicit interface constraints is mostly a language design issue.

Conclusion

The only solution that has a chance to make it into .NET in this decade is to add the IArithmetic<T> interface to the basic data types. But there is really no good reason not to do this as soon as possible. System.Int32, System.Single etc. already implement interfaces such as IComparable<T>, so why not IArithmetic<T>?
As I mentioned before, this would require no compiler or runtime changes. All microsoft would have to do would be to add the IArithmetic<T> interface to the System namespace and let all the basic data types explicitly implement this interface. I have no access to the source code of mscorlib.dll, but at least with mono this is trivial to do.

References

The C# language specification, Version 2.0
The proposed IArithmetic<T> interface
A generic implementation of System.Drawing.Point using IArithmetic<T>
The mono version of the System.Int32 primitive type.
The mono version of the System.Int32 primitive type, enhanced to support IArithmetic<T>

About the Author
Rüdiger Klaehn works as freelance programmer. He is currently trying to start a company with some friends, but in germany that is a long and tedious process. He is very interested in functional programming languages and hopes that .NET will lead to a more widespread adoption in the industry.


If you would like to see your thoughts or experiences with technology published, please consider writing an article for OSNews.

47 Comments

  1. 2004-08-05 5:25 am
  2. 2004-08-05 5:31 am
  3. 2004-08-05 5:54 am
  4. 2004-08-05 6:11 am
  5. 2004-08-05 6:13 am
  6. 2004-08-05 6:30 am
  7. 2004-08-05 6:46 am
  8. 2004-08-05 7:02 am
  9. 2004-08-05 7:37 am
  10. 2004-08-05 8:16 am
  11. 2004-08-05 8:39 am
  12. 2004-08-05 9:18 am
  13. 2004-08-05 10:30 am
  14. 2004-08-05 10:48 am
  15. 2004-08-05 11:44 am
  16. 2004-08-05 12:26 pm
  17. 2004-08-05 12:28 pm
  18. 2004-08-05 1:03 pm
  19. 2004-08-05 1:10 pm
  20. 2004-08-05 1:11 pm
  21. 2004-08-05 1:13 pm
  22. 2004-08-05 1:18 pm
  23. 2004-08-05 1:24 pm
  24. 2004-08-05 1:32 pm
  25. 2004-08-05 1:34 pm
  26. 2004-08-05 2:13 pm
  27. 2004-08-05 3:58 pm
  28. 2004-08-05 4:37 pm
  29. 2004-08-05 4:52 pm
  30. 2004-08-05 5:02 pm
  31. 2004-08-05 5:08 pm
  32. 2004-08-05 5:16 pm
  33. 2004-08-05 5:28 pm
  34. 2004-08-05 5:55 pm
  35. 2004-08-05 6:04 pm
  36. 2004-08-05 7:04 pm
  37. 2004-08-05 7:06 pm
  38. 2004-08-05 8:19 pm
  39. 2004-08-05 8:21 pm
  40. 2004-08-05 8:26 pm
  41. 2004-08-05 8:35 pm
  42. 2004-08-06 9:02 am
  43. 2004-08-06 2:16 pm
  44. 2004-08-06 4:27 pm
  45. 2004-08-06 8:17 pm
  46. 2004-08-10 4:06 pm
  47. 2004-08-12 9:31 am