C# ambiguity in Func + extension methods + lambdas
- by Hobbes
I've been trying to make my way through this article:
http://blogs.msdn.com/wesdyer/archive/2008/01/11/the-marvels-of-monads.aspx
... And something on page 1 made me uncomfortable. In particular, I was trying to wrap my head around the Compose<() function, and I wrote an example for myself. Consider the following two Func's:
Func<double, double> addTenth = x => x + 0.10;
Func<double, string> toPercentString = x => (x * 100.0).ToString() + "%";
No problem! It's easy to understand what these two do.
Now, following the example from the article, you can write a generic extension method to compose these functions, like so:
public static class ExtensionMethods
{
public static Func<TInput, TLastOutput> Compose<TInput, TFirstOutput, TLastOutput>(
this Func<TFirstOutput, TLastOutput> toPercentString,
Func<TInput, TFirstOutput> addTenth)
{
return input => toPercentString(addTenth(input));
}
}
Fine. So now you can say:
string x = toPercentString.Compose<double, double, string>(addTenth)(0.4);
And you get the string "50%"
So far, so good.
But there's something ambiguous here. Let's say you write another extension method, so now you have two functions:
public static class ExtensionMethods
{
public static Func<TInput, TLastOutput> Compose<TInput, TFirstOutput, TLastOutput>(
this Func<TFirstOutput, TLastOutput> toPercentString,
Func<TInput, TFirstOutput> addTenth)
{
return input => toPercentString(addTenth(input));
}
public static Func<double, string> Compose<TInput, TFirstOutput, TLastOutput>(this
Func<double, string> toPercentString,
Func<double, double> addTenth)
{
return input => toPercentString(addTenth(input + 99999));
}
}
Herein is the ambiguity. Don't these two function have overlapping signatures? Yes. Does this even compile? Yes. Which one get's called? The second one (which clearly gives you the "wrong" result) gets called. If you comment out either function, it still compiles, but you get different results.
It seems like nitpicking, but there's something that deeply offends my sensibilities here, and I can't put my finger on it. Does it have to do with extension methods? Does it have to do with lambdas? Or does it have to do with how Func< allows you to parameterize the return type? I'm not sure.
I'm guessing that this is all addressed somewhere in the spec, but I don't even know what to Google to find this.
Help!