posted by Rüdiger Klaehn on Thu 5th Aug 2004 05:00 UTC
IconOne 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> 
{}
Table of contents
  1. "Generics, Page 1/2"
  2. "Generics, Page 2/2"
e p (0)    48 Comment(s)

Technology White Papers

See More