10

I am working in a small educational project where we have to implement a n-dimensional matrix. Depending on the context, this matrix has either to work with our own built-in ComplexNumber struct or with System.Double and for very simple examples, with integral types (mainly System.Int32).

Due to the nature of the application, we are not demanded to implement lightning fast performance.

My first idea was therefore to implement a Matrix<T> where T would somehow need to be restricted to "numbers".

The obvious problem in doing this is that there is no way right now in the language to constraint the generic type T with defined operators. Also I do not see an easy way to restrcit T to reasonable types.

My questions are:

  1. Can somebody please point me in the direction of an elegant way to make mathematical operations with generic types that doesn't compromise performance too much and to somehow make that work with built in types (if possible).

  2. If Eric ever reads this, does this feature (constraining generic types by defined operators) ever come up in hypothetical future versions of C# design meetings and has it ever been close to making it into the language?

I know its easier and better to implement a ComplexMatrix type and create wrappers around it for each matrix "sub-type" (double, integral, etc.) and pay the performance costs of the conversions between our complex type and whichever type the matrix elements happen to be. This question is more out of curiousity on how would someone implement a similar scenario.

InBetween
  • 32,319
  • 3
  • 50
  • 90
  • I would suggest this type of feature on the connect site. It would be interesting to see if others feel the same way. – Gregory A Beamer Jul 14 '11 at 14:33
  • 1
    see also http://stackoverflow.com/questions/3329576/generic-constraint-to-match-numeric-types http://stackoverflow.com/questions/32664/c-generic-constraint-for-only-integers http://stackoverflow.com/questions/1348594/is-there-a-c-generic-constraint-for-real-number-types and http://stackoverflow.com/questions/63694/creating-a-math-library-using-generics-in-c – Ian Ringrose Jul 14 '11 at 14:50
  • 3
    This is a pretty classic example of where it would be nice to have overloaded functions represented by constraints on type parameters, which is exactly how this would be done in Haskell (where it is, indeed, both elegant and efficient). Enough people on the C# team seem to be familiar with Haskell that I'm sure they're aware of the idea and have no doubt discussed it, but I'd hazard a guess that implementing it properly isn't practical. – C. A. McCann Jul 14 '11 at 15:00

4 Answers4

19

If Eric ever reads this,

If you want something brought to my attention, try the contact link on my blog. Or put my full name in the text of the question so that me searching for myself will find me.

does this feature (constraining generic types by defined operators) ever come up in hypothetical future versions of C# design meetings and has it ever been close to making it into the language?

Indeed, this is a frequently requested feature. We've been getting requests for this sort of thing since C# 1.0.

The feature would requires support from the CLR team, not just the language -- it is the sort of feature that we would want to integrate into all our languages, which increases the cost.

The CLR team has expressed interest in features like this, but they also have a lot of competing features that they could be doing, and limited time and effort to implement those features.

There are numerous ways such a feature could be implemented. For example, we could add the ability to specify static methods in interfaces:

interface IAddable<T>
{
    static T operator+(T x, T y);
}

and then

static T Sum<T>(IEnumerable<T> seq) where T : IAddable<T>
{
    T sum = default(T);
    foreach(T item in seq) sum = sum + item;
    return sum;
}    

The idea would be that the interface means "a type that implements this interface must have the given static methods". We'd then make int automatically implement IAddable<int>, and so on.

How do do so efficiently in a world with runtime-generated generic code is an open question.

I hasten to add that this is just a sketch of an idea. There are many ways to implement this sort of feature. The "statics in interfaces" idea is one that has broader usage than just mathematics, and that's attractive to us. If we're going to go to the huge expense of this sort of feature, it would be nice to have a really general, powerful feature rather than one narrowly focussed on math.

On the other hand, the perfect is the enemy of the good; it might be better to just concentrate on the math problem and not go for a more expensive general solution.

It's an ongoing debate. It is definitely on everyone's radar screen, but I would not expect it any time soon. The language designers are all heads-down working on going through the feedback from the async CTP.

As always, Eric's musings about hypothetical future language features of hypothetical unannounced future products are for entertainment purposes only.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    Eh, why not just implement Wadler-style type classes and be done with it? Oh, and toss in higher-kinded generics while you're at it. Also, I'd like a magical pony. (p.s. -- Not making light of the amount of work that goes into language features, just a Haskell enthusiast with a C# day job. ;] Probably unwise anyhow, parameter variance would cause endless headaches.) – C. A. McCann Jul 14 '11 at 17:31
  • @camccann: A lot of questions I get about features not found in the C#/CLR type system basically come down to "we don't have Haskell-style higher types". Remember, in v1 we didn't even have generic types; it is somewhat of a miracle that the geniuses over in Microsoft Research Cambridge gave us so much help getting generics into CLR v2 / C# 2 / etc. Higher types are a really powerful idea, but most practical business programming problems can be solved without them, and it would have been a hard sell getting them added on top of generics. – Eric Lippert Jul 14 '11 at 18:36
  • 1
    The funny part is that a lot of features people would like to see added to Haskell basically come down to "we can't do X like Agda does". It never ends, I suppose! But given the practical considerations C# has to deal with, you guys have done a great job and, as a .NET developer, I really do appreciate it. – C. A. McCann Jul 14 '11 at 20:13
  • @EricLippert What do you think about the way F# addressed this: http://msdn.microsoft.com/en-us/library/dd548046.aspx – AK_ Jun 19 '14 at 20:24
  • @AK_: I am no expert on F#, so comments by me on it should be taken with an appropriately-sized grain of salt. I am generally of the opinion that languages where complex and subtle semantics are encoded in punctuation that has no connection to the semantics make for code that can only be understood by a priesthood. Suppose we swapped the meanings of `'` and `^`; would anyone say "oh, that's obviously wrong!" the way they would if we made `+` mean division and `/` mean addition? The same goes for `*` and `&` in C. – Eric Lippert Jun 19 '14 at 23:18
  • @EricLippert yeah, it might be confusing, but it's just syntax. I was referring to the way the feature works, and how it is implemented, that is without CLR support, and whether something similar might be added to C#. – AK_ Jun 19 '14 at 23:26
3

It depends on your idea of what is elegant. If your idea of elegance to being able to write a+b where a and b are of the generic type, and that would be my idea of elegant, then this cannot be done.

Sadly, C# generics cannot achieve the elegance of C++ templates for this type of code.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Yeah that is what I had in mind. Daniel's solution *does* let you do that but I think performance will suffer with that approach. I'll check it out. I'm wondering if this is a feature that has been requested often enough because it does seem handy on many ocassions. – InBetween Jul 14 '11 at 14:42
2

The only way to achieve this goal somewhat semi elegant is the following: Let the caller specify a delegate for the needed operators and use these delegates.

e.g.:

class Matrix<T>
{
    Func<T, T, T> _add;
    Func<T, T, T> _subtract;
    // ...

    public Matrix(Func<T, T, T> add, Func<T, T, T> subtract, ...)
    {
        _add = add;
        _subtract = subtract;
        // ...
    }
}

var m = new Matrix<int>((a,b) => a+b, (a,b) => a-b, ...);

// Assuming that ComplexNumber has two static methods Add and Subtract
var m = new Matrix<ComplexNumber>(ComplexNumber.Add, ComplexNumber.Subtract, ..);

However, I have no idea about the performance of this approach...

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • 2
    "However, I have no idea about the performance of this approach" => **It will be slow** – Ian Ringrose Jul 14 '11 at 14:42
  • Thanks! That is definitely a nice approach allthough cumbersome if you have to define quite a few operators. This would also cover the type restriction to reasonable types. – InBetween Jul 14 '11 at 14:43
  • @Ian: I would like to have that backed up by facts. – Daniel Hilgarth Jul 14 '11 at 14:44
  • 1
    @Daniel, Calling a function var an indirect address (delegate) will always be slower than executing a single ‘add’ processor instruction. (I don’t know of any CLR runtime that generates copies of method for each passed in instance of a delegate to allow in lining) At some point the size of the matrix will be such that the overhead of calling the delegate will be measurable. (It may however still be fast enough for solving a given problem) – Ian Ringrose Jul 14 '11 at 14:56
  • 2
    Yes, Ian's right, so, depending on your specific circumstances, you might find your app takes 50 milliseconds, rather than 10 milliseconds, to perform the calculation. Time enough to get a really small cup of coffee. ;-) – Enigmativity Jul 14 '11 at 16:11
  • 1
    I wonder if it would be any faster if `Matrix` was an abstract class with an abstract `T Add(T, T)` method? – default.kramer Jul 14 '11 at 16:48
  • 1
    Sane efficiency for this sort of thing requires specialization, either by terribly clever JITing or by compile-time type resolution to generate different methods per parameter type. C++ and Haskell accomplish the latter by very different means, and I don't know how much of the former the CLR does. – C. A. McCann Jul 14 '11 at 17:39
2

One workaround with decent performance (that's still ugly) is using a struct that encapsulates the arithmetic behavior you want.

You first define an interface:

public interface IArithmetic<T>
{
    T Add(T n1,T n2);
}

Then you implement that interface using a struct:

public struct DoubleArithmetic:IArithmetic<double>
{
    public double Add(double n1,double n2)
    {
        return n1+n2;
    }
}

And finally you pass the struct as generic parameter into your type:

public class Matrix<T,TArithmetic>
  where TArithmetic:struct, IArithmetic<T>
{
  private static readonly TArithmetic arithmetic=new TArithmetic();

  void DoStuff()
  {
    arithmetic.Add(1,2);
  }
}

I haven't benchmarked it, but I suspect it's rather fast since generics get specialized for each value type passed into it. That's why DoubleArithmetic is a struct.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • Thanks for the input. This is actually really good, and not that ugly given the fact that the langauge doesn't have the tools to really do this sort of stuff easily. Can you please elaborate why `DoubleArithmetic` would be faster if its implemented as a `struct`? – InBetween Jul 15 '11 at 08:16
  • .net creates different code for every value type parameter you pass into a generic. Reference types on the other hand share one code where every method call goes through the interface. But as I said, I haven't actually benchmarked it, so I don't know when this is actually significant. – CodesInChaos Jul 15 '11 at 08:27