The Weekly Source Code 14 - Fluent Interface Edition
If you're new to this, each week I post some snippets of particularly interesting (read: beautiful, ugly, clever, obscene) source and the project it came from. This started from a belief that reading source is as important (or more so) as writing it. We read computer books to become better programmers, but unless you're reading books like Programming Pearls, you ought to peruse some Open Source projects for inspiration.
And so, Dear Reader, I present to you fourteenth in a infinite number of posts of "The Weekly Source Code." Here's some source I was reading this week.
Over the last year or so I've seen an increase in discussion around so-called "fluent interfaces" in many languages. The addition of extension methods (mixins) to C# 3.0 has caused a flood of interesting (weird?) interface as we as a collective to attempt to make programming as easy as writing prose.
Martin Fowler talked about this in 2005 after a workshop with Eric Evans when they first named them "fluent interfaces." He gives this example:
The simplest example is probably from Eric's timeAndMoney library. To make a time interval in the usual way we might see something like this:
TimePoint fiveOClock, sixOClock; ... TimeInterval meetingTime = new TimeInterval(fiveOClock, sixOClock);The timeAndMoney library user would do it this way:
TimeInterval meetingTime = fiveOClock.until(sixOClock);
Of course, the ubiquitous Ruby example is
20.minutes.ago
Martin makes a great point when trying to put "fluent" APIs in a common OOP context, like that of an object browser with emphasis mine:
One of the problems of methods in a fluent interface is that they don't make much sense on their own. Looking at a method browser of method by method documentation doesn't show much sense to
with. Indeed sitting there on its own I'd argue that it's a badly named method that doesn't communicate its intent at all well. It's only in the context of the fluent action that it shows its strengths. One way around this may be to use builder objects that are only used in this context. - Martin Fowler
Piers Cawley follows up and offers a number of guidelines for use when one is designing these things. See his post for the complete annotated list.
- Hide your working.
- Keep your state to yourself.
- Think really hard about names.
- Take advantage of your implementation language.
- If you have them, blocks are you friends.
- Test first design can be a useful way of exploring what your interface should be.
- Reasonable defaults.
In the .NET space, Ayende's Rhino Mocks are, I think, the first and best example before LINQ that really got it right with syntax like.
Expect
.Call(mock.GetID(1))
.IgnoreArguments()
.Repeat
.Once()
.Return(something);
Similar things are done in Java with their support for mixins, called Static Imports in Java 5.
When fluent interfaces get larger and more complex, they suddenly get called Domain Specific Languages as Peirs points out. But, a true DSL is even easier and might not be fluent at all, but rather customized to the domain:
"It seems that every time someone writes a Ruby library that uses class methods, symbols and hashes reasonably sensibly they get delusions of grandeur and call the result a Domain Specific Language (or maybe an ‘embedded’ DSL)."
Two good examples of libraries as DSLs with some fluent aspects are Why's Hpricot, an HTML Parser for Ruby that looks like this:
#!ruby
require 'hpricot'
require 'open-uri'
# load the RedHanded home page
doc = Hpricot(open("http://redhanded.hobix.com/index.html"))
# change the CSS class on links
(doc/"span.entryPermalink").set("class", "newLinks")
# remove the sidebar
(doc/"#sidebar").remove
# print the altered HTML
puts doc
And Python's Beautiful Soup, also an HTML Parser.
from BeautifulSoup import BeautifulSoup, Tag
soup = BeautifulSoup("Argh!FooBlah!")
tag = Tag(soup, "newTag", [("id", 1)])
tag.insert(0, "Hooray!")
soup.a.replaceWith(tag)
print soup
# Argh!Hooray! Blah!
Back on the C# side, Garry Shutler is creating more fluent assertions using extension methods and lambdas for MBUnit like:
testObject.ShouldBeTheSameObjectAs(targetObject).And.ShouldBeEqualTo(testObject).And.ShouldSatisfy(x => x is Object);
But what's a DSL and what's a Fluent Interface and what's just an API? Martin adds in 2006 (as he continues to write his DSL Book):
For me, a key element is that DSLs are limited both in scope (they refer to a particular domain) and capability (they lack features that are basic for general purpose languages). As a result good DSLs are usually small and simple: hence terms like 'little languages' and 'mini-languages'.
For internal DSLs, the fuzzy boundary is what is an API and what is a DSL. Fundamentally there is no difference, an internal DSL is just an API with a fancy name (as the old Bell labs saying goes: "library design is language design"). Despite this, however, I think there is a different feel when you are working with an API that's written with a DSL feel. Things like a FluentInterface can make working with an API a qualitatively different experience. Thinking in DSL terms makes you think about readability in a different way, exploiting the syntax of the host language to create something that seems to stand on its own - rake is a great example of this. - Martin Fowler
Even scripting languages like PHP are getting on board with fluent interfaces, assuming that "with" in this context makes sense to you.
<?php
private function makeFluent(Customer $customer) {
$customer-> newOrder()
->with(6, 'TAL')
->with(5, 'HPK')->skippable()
->with(3, 'LGV')
->priorityRush();
Ultimately I think Paul Jones nails it when he says "Fluent Interfaces Require Fluent Situations":
"I think, for a fluent interface to be effective, you need situations where you actually have all that information at one time so that you can chain the methods in a fluid way" - Paul M. Jones
Scott Bellware said matter of factly:
"Whether fluent interface is a form of DSL or not, it's obviously a form of fluent interface." - Scott Bellware
Are you exploring Fluent Interfaces?
Shameless Plug: As an aside, one addition thing I'd like to mention is our little Forums over at http://hanselman.com/forum. They are run on excellent JitBit's AspNetForum application, the "little forum that could" in my opinion. There's lots of interesting discussions on many diverse topics, and you can look at just the most recent posts, and every page has an RSS Feed.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter


Microsoft Outlook
Windows Live Calendar
Apple iCal
Google Calendar
