First Class Functions: Having fun with delegates & design patterns

time to read 2 min | 334 words

When writing Rhino ETL, I am getting more and more attached to the idea of first class functions, and their usage. The ability to just send a method (with context!) to be executed elsewhere is amazing. The really nice thing is the ability to express design patterns with focus on the intent vs. focus on the how.

As an aside, this post should make your head hurt.

Let us take a factory, for example:

public delegate WaitHandle WaitHandleFactory();
public WaitHandleFactory CreateWaitHandleForCommand(ICommand command)
{
	return delegate
	{
		ManualResetEvent resetEvent = new ManualResetEvent(false);
		command.Completed += delegate { resetEvent.Set(); };
		return resetEvent;
	};
}

And a decorator:

public delegate void Command();

public Command DecorateWithPerformanceLogging(Command commmand)
{
	return delegate
	{
		DateTime start = DateTime.Now;
		command();
		Console.Write("{0} took: {1}", 
		   DelegateToStringRepresentation(command),
               DateTime.Now - start);
	};
}

And proxy:

public delegate T Fetch<T>();

public static Fetch<T> AddCaching<T>(Fetch<T> fetch)
{
	T cachedObject = default(T);
	bool isCached = false;
	return delegate
	{
		if (isCached == false)
		{
			cachedObject = fetch();
			isCached = true;
		}
		return cachedObject;
	};
}

Aspect Ordination may raise a few eyebrows, but it is a natural extension of the above:

public class CanHaveAspects
{
	public Action<string> PrintHello = delegate(string name)
	{
		Console.WriteLine("Hello, {0}", name);
	};
}

public void HavingFunWithAspects()
{
	CanHaveAspects cut = new CanHaveAspects();
	cut.PrintHello = AddBeforeAspect(cut.PrintHello, delegate { Console.WriteLine("Before") } );
	cut.PrintHello = AddAfterAspect(cut.PrintHello, delegate { Console.WriteLine("After") } );
	cut.PrintHello();
}

public Action<T> AddBeforeAspect(Action<T> method, Action<T> before)
{
	return delegate
	{
		before();
		method();
	};
}

public Action<T> AddAfterAspect(Action<T> method, Action<T> after)
{
	return delegate
	{
		method();
		after();
	};
}

But I have to point out that a function that returns a function that returns a function may get a little hard to follow if you mix threading as well.