Generics in .NET 2.0 SUCK

R

Ruediger Klaehn

Sorry about the harsh language, but I have to vent my anger to somebody who
actually understands what I am talking about. Complaining to my girlfriend
is not going to produce any meaningful results other than straining our
relationship...

I just downloaded Visual C# Express Edition to mess with .NET 2.0 generics.
Being a numerically inclined developer, the first thing I wanted to write
was a generic complex number class. I also have some quite large vector and
matrix libraries that I would love to convert to use generics.

Imagine my surprise when I found out that what I want is basically
impossible. I want a complex number class that can work with any basic data
type like so: complex<float>, complex<double>, complex<decimal> and so on.
This is something that is done very often in C++ and one of the main
applications of generics there.

This was my first try (this is only an excerpt):

struct complex<T>
{
public T re,im;
complex<T>(T re,T im)
{
this.re=re;this.im=im;
}
complex<T> Sum(complex<T> a,complex<T> b)
{
return new complex<T>(a.re+b.re,a.im+b.im);
}
}

Something like this would work in C++, since it does not have constraints on
type parameters. But in .NET, when you specify a type parameter without
constraints it is assumed to be a System.Object, which of course does not
have a + operator.

So I thought, probably there is a way to specify a method constraint for T
such that T must have a certain (static) method or a certain operator
method. But the only thing like this is the new() constraint to specify
that a class must have a default constructor.

My second thought was that there might be some interface like IArithmetic.
This is of course complicated by the fact that interfaces can not contain
static methods. But something like

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

should do the trick. This would not be very elegant, but quite sufficient.
Given that there is an interface called IComparable<T> this should not be
too much to ask. Maybe there should even be something more granular like

interface IAddable<T> {
void Add(T a);
}

....

interface
IArithmetic<T>:IAddable<T>,ISubtractable<T>,IMultipliable<T>,IDivisible<T>
{
}

or something. This solution would be similar to the approach taken with
IComparable and IComparable<T>.

But no such interface exists in the System namespace. So I would have to
wrap all the basic data types into structs that actually implement this
interface, like so:

struct ArithmeticInt : IArithmetic<int> {
private int value;
...
}

struct ArithmeticDouble : IArithmetic<double> {
private double value;
...
}

But this would be a lot of work and, even worse, would lead to absymal
performance since in my experience the .NET JIT compiler is too dumb to get
rid of the wrapper code.

There are of course some workarounds like having a separate type parameter
for the operations, like this:

struct Complex<T,Ops> where Ops:IArithmeticOps<T>
{
...
}

But this yields inacceptable performance.

What is really required is a way to specify *method* *constraints* instead
of just interface constraints and the new() constraint.

Another option would be to allow static methods in interfaces and to provide
an IArithmethic interface in the System namespace, but I would prefer the
first option.

Without something like this, generics are only good for typed collections.
Adding so much new syntax and complexity just to make collections faster
and more type safe seems like a waste of time!
 
R

Ruediger Klaehn

Just to back up my assertion that the .NET JIT is not capable of removing
wrapper code, here is a small benchmark. YMMV, but on my machine the second
loop always takes about twice as long as the first loop. So using wrapper
classes is not an option for performance-critical code.

----------------------------------------------------------------------
#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace ConsoleApplication1
{
interface IAddable<T>
{
void Add(T a);
}
struct AddableInt : IAddable<int>
{
int value;
public void Add(int a)
{
value += a;
}
}
class Program
{
static void Main(string[] args)
{
//This is for the JIT
Test();
//This one is for real
Test();
Console.ReadLine();
}
static void Test() {
int x0 = 0;
AddableInt x1 = new AddableInt();
DateTime time0 = DateTime.Now;
for (int i = 0; i < 1000000000; i++)
{
x0 += i;
}
TimeSpan delta0 = DateTime.Now - time0;
DateTime time1 = DateTime.Now;
for (int i = 0; i < 1000000000; i++)
{
x1.Add(i);
}
TimeSpan delta1 = DateTime.Now - time1;
Console.WriteLine(delta0);
Console.WriteLine(delta1);
}
}
}
 
S

Sam Jost

[...rant deleted...]
Without something like this, generics are only good for typed collections.
Adding so much new syntax and complexity just to make collections faster
and more type safe seems like a waste of time!

Ah well, I think making collections typesafe and faster is worth all the new
syntax and complicity.
Oh, and my girlfriend would probably agree with me, too, she'd love to have
more typesafety! :)

Sam
 
S

Scott Allen

On Tue, 27 Jul 2004 14:47:18 +0200, Ruediger Klaehn

Imagine my surprise when I found out that what I want is basically
impossible. I want a complex number class that can work with any basic data
type like so: complex<float>, complex<double>, complex<decimal> and so on.
This is something that is done very often in C++ and one of the main
applications of generics there.
<snip>

Yes, it is unfortunately impossible. I don't think there is a chance
of this changing for 2.0, but you should take this discussion to the
beta newsgroups and try to influence the future direction, because I
know this very subject is being given some thought:
http://communities.microsoft.com/newsgroups/default.asp?icp=whidbey&slcid=us
Without something like this, generics are only good for typed collections.
Adding so much new syntax and complexity just to make collections faster
and more type safe seems like a waste of time!

It's subjective, but I would have to disagree. Collections are
pervasive in many of the applications I work with, and generics will
make them not only type safe and performant, but also make the code
more elegant.
 
J

Jon Skeet [C# MVP]

Scott Allen said:
It's subjective, but I would have to disagree. Collections are
pervasive in many of the applications I work with, and generics will
make them not only type safe and performant, but also make the code
more elegant.

In particular, the ability to have efficient lists of value types
without boxing will be very nice - a list of bytes will no doubt be
useful in many places where currently we use MemoryStream, etc.

I'm with you - type-safe and efficient collections are very
important...
 
R

Ruediger Klaehn

Scott Allen wrote:

[snip]
It's subjective, but I would have to disagree. Collections are
pervasive in many of the applications I work with, and generics will
make them not only type safe and performant, but also make the code
more elegant.
I guess I overreacted a bit. Of course C# generics are still much faster
than java "generics" and not as complex as C++ templates, and they will be
very useful in many situations.

But the fact that it is not even possible to write a fast generic complex
class is a big disappointment. Especially since it would be extremely
simple to add something IArithmetic<T> to all base data types. After all
they added the generic interface Comparable<T>.

I still don't get why such a simple thing has been overlooked!
 
N

Niki Estner

Beeeeeeeeeeeeves said:
The reason Generics in .NET 2.0 SUCK ?
Likely because they are a complete crib off templates in C++, which ALSO
SUCK!!!


Ever implemented a type-safe list in C#?
You do know what type-safety is, don't you?
And... you do know what a list is?
They are the most POOR idea for a way of programming I have ever seen.

Apparently you're new to programming...

Niki
 
A

Andreas Huber

Ruediger said:
Imagine my surprise when I found out that what I want is basically
impossible. I want a complex number class that can work with any
basic data type like so: complex<float>, complex<double>,
complex<decimal> and so on. This is something that is done very often
in C++ and one of the main applications of generics there.

Welcome to the club :-(

<http://groups.google.com/groups?dq=&hl=en&lr=&ie=UTF-8&threadm=OVjxavQbEHA.
1048%40tk2msftngp13.phx.gbl&prev=/groups%3Fdq%3D%26num%3D25%26hl%3Den%26lr%3
D%26ie%3DUTF-8%26group%3Dmicrosoft.public.dotnet.languages.csharp%26start%3D
525>

Regards,

Andreas
 
K

Kyril Magnos

So, let me get this straight... boxing and unboxing are acceptable practices
in your code? Remind me never to run one of your apps. ;-)

As for a "complete crib off templates in C++"... erm, what do you think most
of the C# language is derived from? C++ style languages (Java, C++, C,
etc..).

--
Kyril

message | The reason Generics in .NET 2.0 SUCK ?
| Likely because they are a complete crib off templates in C++, which ALSO
SUCK!!!
| They are the most POOR idea for a way of programming I have ever seen.
|
<snip>
 
D

Daniel O'Connell [C# MVP]

Niki Estner said:
SUCK!!!


Ever implemented a type-safe list in C#?
You do know what type-safety is, don't you?
And... you do know what a list is?


Apparently you're new to programming...

No, he's just here to complain. I consider him a troll at this point.
 
D

Daniel O'Connell [C# MVP]

Something like this would work in C++, since it does not have constraints
on
type parameters. But in .NET, when you specify a type parameter without
constraints it is assumed to be a System.Object, which of course does not
have a + operator.

So I thought, probably there is a way to specify a method constraint for T
such that T must have a certain (static) method or a certain operator
method. But the only thing like this is the new() constraint to specify
that a class must have a default constructor.

There are some issues with this. The basic types like int, double, etc also
do not have + operators, the + is syntax provided by the compiler, those
types are added using the add instruction. Thus an operator+ constraint
would not do what you wanted.

In the thread Andreas posted I provided a code sample to generate a delegate
for a given type to perform addition, if it was possible. It would have a
performance hit as well, unfortunatly.

To really achieve what you want here, the JIT would have to understand
mathematic operations and generate the proper code for a given generic type.
Its just not so easy as an operator constraint I'm afraid.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top