Standard Generic Delegate Types

Standard Generic Delegate Types

Rate This
  • Comments 21

Hey all, I'm back from my vacation. Two weeks of reading, sailing, kayaking and visiting with old friends has left me a lot more relaxed and sunburnt than when I left. I could use another week, but it's also good to be back.

We're introducing a lot of new features in C# 3.0 which, when combined to form LINQ are really interesting and powerful, but, like the component parts of Voltron, are pretty interesting and powerful just on their own. Lambda expressions, for example, are not just useful for making query comprehensions work. They make functional-style programming in C# 3.0 much more elegant than the somewhat clunky anonymous method syntax from C# 2.0.

We're also introducing a new standard generic delegate type in the LINQ libraries to make delegate declaration easier. In the old days, to create a function that takes an int and returns a function from int to int, you'd have to do something like this:

delegate int D1(int y);
delegate D1 D2(int x);
D2 makeAdder = delegate(int x){
  return delegate(int y){
    return x + y;
D1 addTen = makeAdder(10);

In the new world we'll have these definitions in a standard library:

delegate R Func<R>();
delegate R Func<A1, R>(A1 a1);
delegate R Func<A1, A2, R>(A1 a1, A2 a2);
delegate R Func<A1, A2, A3, R>(A1 a1, A2 a2, A3 a3);
//...etc, up to some reasonable number of arguments

so that you can use them plus lambdas to make the code above far more concise:

Func<int, Func<int, int>> makeAdder = x=>y=>x+y;
Func<int, int> addTen = makeAdder(10);

Here's an interesting fact: there are delegate types which can be defined using the old-fashioned syntax but cannot be defined using the newfangled generic syntax. Void delegates, generic delegates and delegates with out or ref parameters are obvious examples. Can you think of any other examples? Next time on FAIC, I'll post an interesting one. 

  • I'd prefer to reorder type arguments like this:

    delegate R Func<R, A1>(A1 a1);

    delegate R Func<R, A1, A2>(A1 a1, A2 a2);

    delegate R Func<R, A1, A2, A3>(A1 a1, A2 a2, A3 a3);

    It seems more natural.

  • It woild be nice to have System.Action with more type arguments in BCL

    delegate void Action< A1>(A1 a1);

    delegate void Action< A1, A2>(A1 a1, A2 a2);

    delegate void Action< A1, A2, A3>(A1 a1, A2 a2, A3 a3);

    like Func family.

  • Putting the return type first makes it harder to read.  I read "Func<int, double, string>" as "a function from int and double to string".

    Also, it certainly does NOT feel more natural to VB programmers, who are used to the return type coming at the end of a function declaration.  

  • I often want a generic type where the parameter is a value or an object rather than a type: for example I want a class of integers modulo p for some prime number p. The simplest approach is to construct a class IntegerModulo with p as an instance variable along with the particular value k (so the constructor IntegerModulo(k,p) constructs an object representing k modulo p). There are two problems with this: first I may have a lot of IntegerModulo objects with the same p, which is a bit wasteful; and second and more importantly I cannot catch attempts to add two IntegerModulo objects with different values of p at compile time. What I would like is to be able to define a generic type,

    IntegerModulo<7> for example, but this is not easy to do. I could construct a class to represent the value 7 using reflection.emit, but this is very cumbersome. Do you have any suggestions?

  • Last time I mentioned that one of the subtleties of programming language design is weighing the benefit

  • Last time I asked whether there were examples of delegate types which could be declared with the traditional

Page 2 of 2 (21 items) 12