Wednesday, April 8, 2009

Another Thing to Add to My C# Wish List

So I've been plagued by this problem lately it seems.

C# is an object oriented language. It wasn't originally built to be functional, but it now has some functional elements, such as lambda expressions and Linq. Lately, I've been learning alot about functional programming via F#. I've actually grown to love the concept of "programming without side effects" that functional programming has to offer, and I was recently working on a small bit of code that (hopefully) would encourage me more to introduce some functional concepts into my code.

Here was my first attempt:


public static class FuncExtensions
{
public static Func<T1, T3> ComposeWith<T1, T2, T3>(this Func<T1, T2> _this, Func<T2, T3> other)
{
return new Func<T1, T3>(o => other(_this(o)));
}
}

class Program
{
static void Main(string[] args)
{
new Func<DateTime, int>(GetYear).ComposeWith(ConvertToDouble)(DateTime.Now);
}

static int GetYear(DateTime dt)
{
return dt.Year;
}

static double ConvertToDouble(int value)
{
return (double)value;
}
}


Okay, so that didn't work out too well. I received the following error:

The type arguments for method
'ConsoleApplication2.FuncExtensions.ComposeWith(System.Func,
System.Func)' cannot be inferred from the usage. Try specifying the
type arguments explicitly.


Hooray. Obviously, this won't work. But my question is "why not?" I mean, after all, you can do something like this:


Func<DateTime, double> func = x => ConvertToDouble(GetYear(x));


Sure, some of you might be asking why I would even want to have a .ComposeWith method like what I defined before. Most object oriented developers would wonder the same thing, but seeing an F# equivalent (data types aside) of the code might help you understand why:

open System

let convertToDouble i = double i
let getYear (d:DateTime) = d.Year
let func = getYear >> convertToDouble
func DateTime.Now |> printfn "%f"


Now, don't get me wrong. I'm not complaining about C#, or saying that C# is an inferior language or anything like that. I typically take issue with people who start using a language and then harp on it constantly about how much they hate it. I love C#. It's what brings the bacon home, and it's an excellent general purpose language to do (almost) everything, but the future is coming, and the idea of "programming without side effects" is a very popular one in the world right now, and will probably gain even more support over the coming years. I don't want C# to turn into a functional language, but I do feel that compatibility and support for a functional programming style may be very important in the next few years.

Besides, I'm not talking about recreating the wheel here. I'm talking about generic type resolution. Type resolution is already used in delegate instance assignment ("Func<DateTime, int> func = GetYear;"), lambda expressions, and the syntax to attach event handlers to events. It would be nice to see this applied more consistently across the C# spec, namely using the same kind of type resolution with non-anonymous methods. This would allow C# methods to be treated almost like first class citizens of the type system, and would allow for a richer experience when it comes to writing code without side effects. While it's possible to code without side effects in C#, it seems as though the number of hoops one has to jump through to get there almost discourages the practice.

The above main method has to be refactored as follows in order to work properly in C#. Notice the explicit type declarations (in addition to the fact that the method is required to be wrapped in a Func<T, TResult> type in order for the extension method to work properly:


static void Main(string[] args)
{
Func<DateTime, double> func = new Func<DateTime, int>(GetYear)
.ComposeWith<DateTime, int, double>(ConvertToDouble);

Console.WriteLine(func(DateTime.Now));
}


It just seems a little kludgy from a functional programming perspective, while it seems perfectly reasonable from an object oriented perspective. After all, there's the level of abstraction of forcing a function into an object (via the Func<T, TResult> constructor), which would be consistent with the object orientation of the language, nevertheless, it'd be nice to write code that looks like this:


Func<DateTime, double> func = GetYear.ComposeWith(ConvertToDouble);