So I was musing the other day on the idea of 'fluent interfaces'. The purpose of a fluent interface is to make it easy to write a line of code that accomplishes a sequence of related tasks, usually by allowing you to chain together a series of method calls on the same object.
Often, discussion of such interfaces is muddied by specious claims that the resulting code 'reads just like English', or that such an API constitutes a domain-specific-language, or DSL - even terminology god Martin Fowler says "in many ways the two terms are synonyms". But then it usually degenerates into a slanging match between dynamic language advocates and Ruby-hate trolls. That's the Internet for you.
Ignoring all that, though, in my primary development language, which is C#, any series of method calls is going to be interspersed with parentheses and dots and camelCased identifiers, making it highly dubious to claim that any stretch of C#, no matter how fluent, 'reads just like English'. But by setting myself a slightly less lofty goal, I think I've actually come up with an example fluent interface that might actually qualify as a DSL, and while it doesn't read 'just like English', it does read 'kind-of just like' another language. Here's a snippet of code to whet the appetite:
turtle
.PenDown
.Forward(20)
.Right(90)
.Forward(20)
.Right(90)
.Forward(20)
.Right(90)
.Forward(20);
Now that takes me back to when I used to do proper programming. Back in what must have been 1988 or so, presumably as a result of demonstrating shocking incompetence with saws and hammers, I spent a happy term's worth of CDT lessons (and a few breaktimes and lunchtimes) writing Logo programs on an Acorn Electron to drive a variety of robotics devices. Later, I moved on to coding pathfinding routines in Logo for a cannibalised Big Trak with a pair of microswitch 'feelers' on its nose, its control-panel gouged out, and a ribbon-cable umbilical soldered into the gaping hole in its back, connecting it back to the Electron. I can still remember that unique workshop smell of fine sawdust gently cooking on the Electron's motherboard...
Actually, now that I think about it I do find myself wondering whether Mr Julian knew that the program he asked me to write to give correct change from a coin dispenser was essentially a knapsack problem... at the time I remember struggling for ages thinking 'there has to be a way to just figure out how many coins to hand out that doesn't involve all this looping and backtracking' - only writing this article now did it suddenly hit me that there really wasn't.
But I digress - we were talking about fluent interfaces. Now, an argument could certainly be made that Logo is a domain-specific-language for turtle graphics. Actally, Logo is a fully capable programming language with functional overtones - designed, like BASIC, with teaching in mind, but with variables and subroutines and much more besides. But it also contains a lot of domain-specific constructs for moving a turtle along a path - be it a triangle moving around on a screen leaving pixels behind, or a robot moving around on the floor dragging a felt-tip (or a Big Trak repeatedly bumping into a table leg, for that matter).
Flogo, then, is an attempt to implement a Logo-like syntax for rendering turtle-graphics into a GDI+ Graphics context, using a fluent C# API.
Now, the example code above is very basic - you can pretty much see how it'd be implemented. But it's also pretty lame step-by-step Logo programming - more of an Etch-a-sketch than the Spirograph that proper Logo is able to simulate. It would be much nicer if we could write something more like Logo's looping syntax - something like this:
turtle
.Repeat(4)
[
.Forward(20)
.Right(90)
]
But that's not valid C#, so we're not going to be able to do that. But we can actually do something remarkably similar - at least in C# 3.0...
turtle = turtle
.Repeat(4)
[ t => t
.Forward(20)
.Right(90)
];
Not a bad syntax compromise... and I can tell you, it makes Flogo a lot more interesting, and potentially a lot more powerful.
In the next part, we'll take a look at the code that makes that possible, and some intriguing capabilities that arise as a result. After that, we'll maybe take a look at how some ideas from functional programming help make this into a really powerful little toy.
Although still maybe not as powerful a toy as a Big Trak wired up to an Acorn Electron...