First Class Functions: Having fun with delegates & design patterns
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.
Comments
I actually just wrote a post about using first-class functions for UI thread-safety: http://kohari.org/2007/08/03/thread-safe-event-handlers/
I'm with you, they're really useful. Can't wait for C# 3.5 to become production-ready so I can use lambda syntax instead....
Its great isn't it?
I don't think it will be difficult to follow if we get good names, and more concise syntax.
I'm not sure if the Func<,,,> delegates are going be to good names or not. In many ways they are good, because they tell us right there in line what types are expected, but they are also bad. They are not very descriptive.
Of course Lambda's will make it far more concise and readable IMO.
Comment preview