Constrained dot-chaining

For my recent XML parsing library -- DeclarativeXMLParser -- I used a coding technique that I call constrained dot-chaining. This technique is useful for creating structures in code that more concisely express their intent.

Simple dot-chaining is accomplished by declaring methods that end in "return this". For example, StringBuffer in Java and StringBuilder in C# both facilitate dot-chaining by returning "this" from the "append" (or "Append" in C#) method. Thus you can chain a series of method calls as in:

String greeting = new StringBuffer()
  .append("Hello, ")
  .append(name)
  .append("!")
  .toString();

Notice the use of the dot at the beginning of the line. As compared to the more typical dot at the end of the line, this lends more symmetry to dot-chained code and works better with intellisense.

Dot-chaining is especially powerful when you pass the resulting object as a parameter. The object can be created and initialized in-line with no semicolon. No variable needs to be declared.

throw new MyException(new StringBuffer()
  .append("Failed to open  file ")
  .append(fileName)
  .append(": ")
  .append(e.getMessage())
  .toString(), e);

Constrained dot-chaining is useful when the order of operations should be restricted. For example, in the DeclarativeXMLParser, each element will be initialized before the attributes are matched. The attributes will be matched before the Begin delegate is called. Begin will precede the sub elements, and End will follow all. So you want the code to look like this:

new Element()
  .Init(delegate() {...})
  .RequiredAttribute("id", idAttribute)
  .IgnoreOtherAttributes()
  .Begin(delegate() {...})
  .One("subElement", new Element()
    .RequiredAttribute("name", nameAttribute)
  )
  .End(delegate() {...});

Unconstrained dot-chaining would allow these operations to be declared in any order. While that wouldn't confuse the parser engine, this would most certainly confuse anyone reading the code. Constraints are required to force this code to be more readable.

Here's my solution
The Element class is only the leaf of a long line of inherited classes. It directly supplies the Init method, which returns Element. It's base class is ElementWithAttributes, which supplies all of the attribute related methods. ElementWithAttributes in turn inherits ElementWithFilter, which supplies the Filter method, and so on up the hierarchy until you reach ElementWithEnd.

The idea is simple. Once you go up the inheritance hierarchy, you can't go back down. This forces you to call the methods in the prescribed order. Inheritance allows you to skip levels if you want to, but you can't backtrack.

Each level of the hierarchy returns its own type for methods that can be called more than once, and its base class type for methods that can be called only once. So, for example, once you call Begin, you are now at the ElementWithContent level. You cannot call Begin again because you are too high up in the tree.

Download the code for more details. I hope you find this technique as useful as I have.

Leave a Reply

You must be logged in to post a comment.