dharmatech
dharmatech

Reputation: 9497

Function composition

Below a Compose function. If f and g are unary functions which return values, then Compose(f,g) returns a function which when called on x performs the equivalent to f(g(x)).

static Func<X, Z> Compose<Z, Y, X>(Func<Y, Z> f,Func<X, Y> g) 
{ return x => f(g(x)); }

Here's a couple of simple Func values which can be composed:

Func<int, bool> is_zero = x => { return x == 0; };

Func<int, int> mod_by_2 = x => { return x % 2; };

E.g. this works:

Console.WriteLine(Compose(is_zero, mod_by_2)(4));

However, if I instead have these equivalent static methods:

static bool IsZero(int n) { return n == 0; }

static int ModBy2(int n) { return n % 2; }

the same example doesn't work with those. I.e. this produces a compile time error:

Console.WriteLine(Compose(IsZero, ModBy2)(4));

Explicitly passing types to Compose fixes the issue:

Console.WriteLine(Compose<bool, int, int>(IsZero, ModBy2)(4));

Is there anyway to write Compose such that it works on the static methods without the explicit types?

Is this a good approach to take to implementing Compose? Can anyone make improvements to this?

Upvotes: 9

Views: 2400

Answers (1)

JaredPar
JaredPar

Reputation: 754525

The problem here is not the use of static methods but the use of method groups. When you use a function name as an expression without invoking it then it's a method group and must go through method group conversion. You would have the exact same problem with instance methods.

The problem you're running into is that C# can't do return type inference on method groups. Using Compose(IsZero, ModBy2)) requires the return type to be inferred for both IsZero and ModBy2 and hence this operation fails.

This is a known limitation in the inference capabilities of the C# compiler. Eric Lippert wrote an extensive blog article on this particular subject which covers this problem in detail

Upvotes: 10

Related Questions