This is an exploration of the limits of C# - how much it could be pushed to create Fluent APIs or Internal Domain Specific Languages (DSLs) that have different kinds of flow than the traditional use of the language. On the way we look at indexers, implicit cast, delegates and operator overloading, and use them - sometimes in a bit unexpected ways.
The example that I use is an API for generation of XML / (X)HTML with more Fluent syntax. Let's call it Fluent.Xml.Linq.
I have included some code as screenshots, because styling is so important for the purposes of this article, but you can find all the source in the accompanied ZIP-file.
I love C#, I am a huge fan of Anders Hejlsberg, but there is one thing I am envious of Visual Basic developers of: Quite often you need to produce XML or (X)HTML within code, and they've got this great language feature called XML literals. You are probably familiar with that, but here is an example just in case:
Now, if the software that you are writing does a lot of XML production, you should really consider template technologies - my favorite is StringTemplate - but often, it is just some XML blocks here and there, and it is not really worth the extra DLL references. String concatenation is one option, but let's say we want to stay somewhat strongly typed...
I was thinking to first show here the above VB-example using
System.Xml.XmlDocument. It would probably be dozens of lines of code. But then, I thought it is waste of space: most of you - if not all - are already familiar with
System.Xml.Linq, so this is what the above example would look using LINQ to XML:
Well, it is not bad compared to
System.Xml, but there are some problems:
- Readability is not really good: what jumps to your face is all those "
XElement" and "
XAttribute" terms instead of the actual point: the XML elements and attributes.
- Tag and attribute names are strings - not strongly typed, so it is easy to make such mistakes as "Type", "types" or "tyoe" instead of "type"
Really, what I would like to write is something like this:
It would be easy to create a DSL like that - using Oslo/MGrammar tools, or my favorite Antlr tools. But everyone who has tried creating DSLs knows that while there are quite good tools for creating the actual parsing of DSLs and using DSLs as stand-alone programs, the deployment, maintenance, and IDE integration are still very hard.
Hopefully, in the future, Microsoft will get their DSL story straight so that it would be easy to mix, e.g., C# and DSLs within Visual Studio. But for now, what I would really like to do is to be able to write this kind of syntax in C#.
Well, this article is an exploration of how you could do that.
Attribute syntax - indexer and implicit cast
The first thing that we should tackle is the easiest part - the attributes. It is easy to create an indexer to get the
attrName["attrValue"] syntax. You could just create a class like this:
public class FXAttrDefinition
private XName name;
public FXAttrDefinition(XName name)
this.name = name;
public XAttribute this[object value]
return new XAttribute(this.name, value);
... which would allow you to create the attributes like this:
FXAttrDefinition type = new FXAttrDefinition("type"), value = new FXAttrDefinition("value");
XElement input = new XElement("input", type["text"], value["Default value"]);
but the constructors are really long to write like that - they take too much space. You could easily have dozens of different attributes even for simple HTML. Couldn't we replace them with something nicer?
What we can do is make an implicit cast so that our
FXAttrDefinition class can be automatically converted from
string the same way as
double is converted from integer or
XName is automatically converted from a
string. You do it like this:
public static implicit operator FXAttrDefinition(string name)
return new FXAttrDefinition(name);
public static implicit operator FXAttrDefinition(XName name)
return new FXAttrDefinition(name);
I decided to also allow the cast from
XName, so that you can use the XNamespace + string => XName construct, which is the way of LINQ to XML to create namespaces. So, now you could use the code like this:
FXAttrDefinition tpe = "type", val = "value";
XElement input = new XElement("input", tpe["text"], val["Default value"]);
Now, that starts to be quite succinct as far as the attributes are concerned.
Next, we should take care of the
XElement. You could of course use the exact same structure as with attributes - there is an example of that as the
FXElemDefinition2 class in the sample files. However, it is not quite what I am looking for. Just look at the result:
Firstly, we are using an
object array (marked "
params") as the indexer! Yes - to my surprise - it is allowed, and it works, but it is starting to be a bit strange if you think about the intended purpose of indexer as a language feature.
More importantly, to my quest for that perfect XML generation syntax, readability is better in my first example where we have round brackets () around element children and square brackets are reserved for attribute value.
So, how can I get those round brackets?
Element syntax - delegates
Of course, you could just create static methods to your class for each of the elements you are going to use. But then, you would end up having each of the XML generating classes cluttered with dozens of methods like
input() etc. Unacceptable!
Or, if there was a separate class, you would need to first instantiate it"
var x = new FunctionCollection();. Then, you would use syntax like
x.form(). OK, best option so far, but I really want to get rid of that
Delegates are an important language feature introduced in C# 2.0. They are basically functions assigned to a variable. These functions can be static, from instantiated objects, or even anonymous. We can use them like this to get our nice function-syntax on elements:
delegate XElement FXElemDefinition(params object children);
XElement pDel(params object children)
return new XElement("p", children);
XElement inputDel(params object children)
return new XElement("input", children);
private void getElemExample()
FXElemDefinition p = pDel, ipt = inputDel; ;
XElement elem = p(ipt(new XAttribute("type", "text")));
We define a delegate named
FXElemDefinition and we define functions for paragraph and input. OK, so now our element syntax is the way I want it, but how can we get rid of that boilerplate code of defining functions?
Let's take a step back and think what we are doing: We need to call a constructor (= function)
new XElement() with two parameters:
children. But, we assign the variable
p to be another function that already knows the element name "p", and thus we can call it just with the
children parameter. So essentially, we want to reduce the function from having two parameters to only one parameter. This is called currying, and it is a much used mechanism in functional languages. In C#, it is a bit limited. For example, it does not play well together with the "
params" keyword, and I had real trouble implementing it first. But fortunately, there is one syntax that we can use in our case:
FXElemDefinition p = x => new XElement("p", x);
FXElemDefinition ipt = x => new XElement("input", x);
But that's really messy, the syntax is not intuitive unless you have worked with lambdas a lot. And again, any real-life XML generation scenario would have a lot of different elements. Can we use implicit cast again to make it shorter?
Unfortunately: not! The
delegate class is marked
sealed so we cannot touch that (probably for a good reason :-). We cannot do casts or operator overloading unless we are able to extend the class. We can, however, create a helper class like this:
public delegate XElement FXElemDefinition(params object children);
public class FXElementHelper
public FXElemDefinition this[XName elementName]
return remainingChildrenParam =>
new XElement(elementName, remainingChildrenParam);
and then we can call it like this:
var h = new FXElementHelper();
FXElemDefinition p = h["p"], ipt = h["input"];
XElement elem = p(ipt(new XAttribute("type", "text")));
So now, we have achieved our goal and can create XML/XHTML, with quite nice syntax like this (FluentSample.cs in the source code):
If I knew how, I would get rid of the
h[""], but I can live with this syntax. It is nice to read - you get the structure of the HTML immediately: wlement and attribute names are first defined, and after that, they are strongly typed. It is quite fast to write, and supports intellisense nicely.
I actually started writing this article thinking that the DSL that I would demonstrate would use operator overloading. You know, the XML element would be created like an expression:
There is an unfinished - but somewhat working - example of this in the "Old" folder of the source code if you are interested. But I just couldn't get it "flowing fluently" enough using operators. The problem is the hierarchical structure of XML: the Nested Functions approach is much more natural.
But I am sure there are good uses for operator overloading in Internal DSLs that have other purposes than XML. I also think that this method could be used more than it is now to produce more intuitive and naturally flowing syntax. One good example I already mentioned above is the
XNamespace, which overloads the plus operator when the second operand is
XNamespace ns = "MyNameSpace";
XName qualifiedName = ns + "tagName";
But you could get so much further with this: overloading different operators (*, /, -, ==) and so on to build complete expressions. Perhaps, I will figure out a good example and write about it someday.
Background on Fluent APIs / Internal DSLs
The term of Fluent Interfaces (or Internal DSLs) was introduced by Martin Fowler as he, in 2005, described the then new style of interfaces that were often characterized by the use of method chaining. I decided not to cover method chaining here as it is so well known these days. Just put "Fluent" in the CodeProject search box or "Fluent API" in Google, and you will find several examples. I am sure you will recognize the style - even if you didn't recognize the term.
I would say LINQ to XML is already an example of a Fluent interface. Sure, it does not use method chaining using dots, but it uses the most natural way of constructing XML trees: hierarchical function structure (or Nested Functions, as Fowler describes in this article). In that sense, it satisfies Fowler's description of "intent is to do something along the lines of an internal Domain Specific Language" and "the API is primarily designed to be readable and to flow".
What I tried to demonstrate above is ways to take that "fluency" one step further using other language features that are available to us in this great language of C#.
To me, the pros of these kinds of approaches are clear: APIs like this are easier to read and write:
- Less time
- Less money
- Better understanding for someone else than the person who wrote it
- ... or for yourself, if you need to look at old code years later
The main downside is as Fowler wrote in the original article:
"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 a method by method documentation doesn't show much sense to [function named] 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."
Well said. I would only like to add to this a few aspects: Often in Fluent APIs, certainly in the examples above, you are "bending" the original intent and conventions of the language (say, for example, using indexers when there is really no collection :-). For someone who is not familiar with your DSL and the intention of it, this might be confusing.
Another thing is that making a good Fluent API is an effort. It is much faster to create a traditional API. In fact, Fowler suggests - and I agree - it makes sense to first create a traditional API and then create the Fluent API on top of it.
So, there are serious pros and cons in Fluent interfaces. This is still kind of a new approach - experience is limited. Whether you use this stuff or not in your projects is in your discretion - well, like any other pattern I suppose. It's just an idea.