Thursday 29 May 2008

Ayende's weird code

I spent the better half of yesterday evening playing with some code that Ayende posted. He wanted to make this compile:

public interface IDuckPond
    Duck GetDuckById(int id);
    Duck GetDuckByNameAndQuack(string name, Quack q);

IDuckPond pond = null;
pond.Stub( x => x.GetDuckById );
pond.Stub( x => x.GetDuckByNameAndQuack );
My first reaction was WTF! I didn't understand at all what he was getting at, but obviously he was making sense to some people, as the meaningful (but initially over-my-head) comments were quickly piling up. Lets take a look. The interface definition is completely standard, nothing out of the ordinary at all. The weird bit is definately this Stub method. It appears to be a void method that accepts a lambda expression as its only parameter. But hang on a sec, lets forget the lambda expression for a second; this method isn't declared on the IDuckPond interface, and aren't we going to get a null reference exception anyway? Well, not if Stub is an extension method. Now its certainly unclear to me how Ayende was going to do anything meaningful within the extension method given that you can't use the ref or out keywords on the target of an extension method so you are still gonna be stuck with pond = null after the first stub call returns, but nevermind that. So the extension method is going to look something like this:
static class StubExtender
    public static void Stub(this IDuckPond pond, SOME_LAMBDA_THINGY)
Where SOME_LAMBDA_THINGY is obviously the lambda expression parameter bit. So what goes there? Well, lets take a look at the first lambda expression that gets passed to Stub:
x => x.GetDuckById
This certainly had me puzzled at first. He's not calling GetDuckById here, because there is no argument.. so what's going on? Thinking about it a bit I realised that the x.GetDuckById is a delegate, which means that the parameter to the Stub method is a function that returns a function. Brain starting to hurt yet? If so, you must be a functional programming newbie like me. Having made this realization, it was pretty quick to get the code compiling. I defined delegates for the two methods on IDuckPond:
delegate Duck GetDuckByIdDelegate(int id);
delegate Duck GetDuckByNameAndQuackDelegate(string name, Quack quack);
And then two overloads for the stub method:
public static void Stub(this IDuckPond pond, Func<IDuckPond, GetDuckByIdDelegate> func) { }
public static void Stub(this IDuckPond pond, Func<IDuckPond, GetDuckByNameAndQuackDelegate> func) { }
Okay, so the first overload takes a function that takes an IDuckPond and that returns a function with GetDuckById's signature. The second overload does the same thing but its parameter is a function that returns a function with GetDuckByNameAndQuack's signature. I quickly realised that I don't actually need the explicitly declare delegates, because I can just use the framework delegate Func, which I was already doing anyway. So the delegates got deleted and the overloads became this:
public static void Stub(this IDuckPond pond, Func<IDuckPond , Func<int, Duck>> func) { }
public static void Stub(this IDuckPond pond, Func<IDuckPond , Func<string, Quack, Duck>> func) { }
So this was better, but certainly not perfect. It was obvious that Ayende was looking for a general solution. The first generalization was simple.. make the stub method generic on the extension target:
public static void Stub<T>(this T obj, Func<T, Func<int, Duck>> func) { }
public static void Stub<T>(this T obj, Func<T, Func<string, Quack, Duck>> func) { }
The cool thing about this is that I didn't have to change the calling code at all. Specifically, I don't have to call pond.Stub<IDuckPond>(etc) - why? Because the compiler does generic parameter inference; it is able to determine that the type T is IDuckPond because we are passing in an IDuckPond as the first argument. But obviously this is still not ideal because as you add new methods to your interfaces, you will need to add the appropriate Stub overloads. You could probably code gen them, but code generating just for the sake of nice syntax seems to be taking things a bit far. I wanted to see if I could come up with anything nicer, and some of the comments in the thread gave me some ideas. This one is okay:
IDuckPond d = null;
d.Stub(x => (Func<int, Duck>)x.GetDuckById);
d.Stub(x => (Func<string, Quack, Duck>)x.GetDuckByNameAndQuack);
static class StubExtender
   public static void Stub<T, U>(this T obj, Func<T, U> func) { }
At least this way we can get by with just one definition for Stub, though at the cost of adding some casts. Now why did I have to add those awful casts? Well I modified the Stub method to be generic, but the compiler can't infer the generic parameter U like it is with T. Why? Lets say that IDuckPond had a third method, an overload of GetDuckById:
interface IDuckPond
    Duck GetDuckById(int id);
    Duck GetDuckById(object o);
    Duck GetDuckByNameAndQuack(string name, Quack quack);
Now when we say x.GetDuckById, its unclear which overload we are referring to, and its important because the delegates would have different signatures. As a result of this fact, the compiler cannot infer the type, so you have to give it explicitly, by casting. Some other neat alternatives were suggested by Jacob Carpenter, you can find those in the comment thread for Ayende's post if you are interested. He's doing something tricky with the default keyword, some investigation is in order methinks. Unfortunately there does not appear to be a perfect solution. You can't get away with the exact code that Ayende specified without writing or generating all the required overloads. I really enjoyed this little challenge, its reminded me that I'm not as good with C# as I would like to think, and instilled me with the urge to do more weird stuff. Expect more posts filled with angle brackets!

Thursday 22 May 2008

The Mythical Man-Month

Phew, has it already been a month since my last post? There's no doubt about it, GTA IV is to blame. In any case, I haven't been slacking off completely. I just finished reading the rather short and positively ancient The Mythical Man-Month: essays on software engineering by Fred Brooks. This book is considered to be one of the classics. It appears in "must read" lists all the time, and is constantly references by software bloggers around the world.

Originally published in 1975, this book is older than me. I'm reading the 20th anniversary edition which has some added chapters, but the original contents are left as they were - and it sure does show. The book is more about software management than engineering and if offers several valuable ideas, but its also full of discussion that is simply not at all relevant to software engineering today.

The book makes the point that you can't rush software. Doubling your staff will not halve your schedule, and adding manpower to a late software project will probably just make it later. It tackles this concept that men and months are not interchangeable from a number of different angles, and while I consider this idea to be blindingly obvious today, I can appreciate it might not have been quite that way 33 years ago. The 20th anniversary edition contains the "No Silver Bullet" essay which was written about a decade after the first printing of the book. This essay claims that it is unreasonable to expect that any single technological or methodological advance will deliver an order of magnitude improvement to software productivity. Developing software is an inherently difficult complex process, and we can chip away at the difficulties from many different angles, and perhaps achieve order of magnitude improvements through combination of many tools and techniques, but there is no discovery waiting around the corner that will improve our software development productivity by a factor of 10.

I think these ideas are worth reading about, and the book has certainly broadened my perspective and given me insight to how people thought about software development many years ago. However, that said I am reluctant to recommend this book. MUCH of it talks about the practicalities of software development circa 1975 - so its filled with arcane meaningless terms from an era long gone. I couldn't help but laugh at the idea of embedding documentation into code having the downside that "you have to store more characters". I'm now wishing I was taking notes as I read because there were some real whoppers in there, stuff that really makes me appreciate how far we've come. But while some of it was funny, most of it was just snore worthy.

We need a modern replacement for this book. A text that communicates some of the old but worthwhile ideas along with some the new, such as iterative development. A text that I could give to someone else and not have them hand it back upon the first mention of some obscure mainframe operating system that I or they haven't heard of. And while I'm at it: a text that does not make the assumption of the existence of this abstract concept of "God" several times would also be nice - there is no place for that sort of thing in a software text. The man-month ain't the only concept mentioned in this book that I consider to be mythical.

Maybe such a book does exist, and I just don't know about it yet. If you think you've found it, be sure to let me know!