InfoQ

News

Extension Methods, DSLs, and Fluent Interface

Posted by Jonathan Allen on Nov 23, 2007 06:12 AM

Community
.NET
Topics
Domain Specific Languages
Tags
Visual Basic.NET ,
C# ,
Orcas

What is the difference between an Internal DSL and an API? Martin Fowler described an internal DSL back in February of 2004 as,

The lisp and smalltalk communities also have a strong tradition of DSLs, but they tend to do it another way. Rather than define a new language, they morph the general purpose language into the DSL. (Paul Graham describes this well in Programming Bottom-Up.) This Internal DSL (also referred to as an embedded DSL) uses the constructs of the programming language itself to define to DSL. This is a common way to work in any language, I've always thought of defining functions in such a way to provide a form of DSL for my problem. But lispers and smalltalkers often take this much further. Another term for an API written in this style is FluentInterface.

Two and a half years later he says,

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.

So what exactly does an Internal DSL look like? Usually the answer comes back as an example of fluent programming. In fluent programming, all methods return either the same object or a new object. This allows method calls to be chained together.

For an example, we turn to an excerpt from Neal Ford's QCon presentation "Building DSL's in Static and Dynamic Languages".

def c = 2.days.fromToday.at(4.pm)

Until recently hacking interstice classes like integer required a dynamic language like Ruby or Python, specifically because they provide something called "open classes". An open class allows one to add new methods to a class at runtime.

So what does this have to do with a .NET developer using C# or VB? Well, C# 3 and VB 9 both support something called Extension Methods. Extension methods allow users to statically add methods to a pre-existing class. You could for example create a "days" method that takes an integer and returns a TimeSpan.

Consider the difference between this C# 2.0 code and the same thing written in C# 3.0.

//C# 2.0
date d = Helper.At(Helper.FromToday(Helper.Days(2)), Helper.Pm(4));
//C# 3.0
date d = 2.Days().FromToday().At(4.Pm);

It should be noted that these two lines of code compile to exactly the same thing. All the heavy lifting was done by the compiler and the Extension attribute.

A final tip for using extension methods. Though officially supported only in .NET 3.5, Jared Parsons found a way to use extension methods in .NET 2.0. Basically it comes down to creating a fake "ExtensionAttribute" class that the new compilers confuse for the real one.

I guess they could have done it better by Sadek Drobi Posted Nov 23, 2007 4:34 PM
Wrong .NET 3.5 sytanx by Seth Yuan Posted Nov 23, 2007 8:09 PM
Re: Wrong .NET 3.5 sytanx by Jonathan Allen Posted Nov 25, 2007 3:32 AM
Fuzzy Border by Phillip Calçado Posted Nov 27, 2007 12:14 AM
  1. Back to top

    I guess they could have done it better

    Nov 23, 2007 4:34 PM by Sadek Drobi

    I am one of the biggest fans of c# 3.0 features. Yet I guess that there are things that could have been done better. One of them is this "Extension Methods" story. First of all thank you for gently pointing out that both the above lines of code compile to the same thing, but who else will? In ruby case, code still belongs to the object, even when we reopen classes, we add methods to that same object. That means we are keeping our modularity. We should be very careful using extension methods. I guess C# team chose the easiest solution, which is to implement such a specific feature. And worse to overload the "." to handle two different things! Yes, two completely different things. I guess it won’t be less fluent to use the "#" character, or any other that shows the difference. Well even better, to allow an open compiler, and to add a macro mechanism for such a syntactic sugar. Because it, as they like to say, all is about syntactic sugar...

  2. Back to top

    Wrong .NET 3.5 sytanx

    Nov 23, 2007 8:09 PM by Seth Yuan

    Extension methods means to methods, not properties. So I think you forgot to put parenthesis around those method calls.

  3. Back to top

    Re: Wrong .NET 3.5 sytanx

    Nov 25, 2007 3:32 AM by Jonathan Allen

    Yep, you caught me. I have to admit I do so much VB programming I forget that C# requires empty parenthesis sprinkled all over the place.

  4. Back to top

    Fuzzy Border

    Nov 27, 2007 12:14 AM by Phillip Calçado

    Sating the differences (if any) between DSLs and Fluent Interfaces is a very hard thng. I have some points here: http://fragmental.tw/research-on-dsls/language-adaption/

Educational Content

Bindings, Platforms, and Innovation

This presentation focuses on the Internet and separating myth from fact, history from the future, and the mundane from the imaginative. Bob Frankston presents a vision of what could and should be.

Orchestrating Long Running Activities with JBoss / JBPM

This article explores the use of JBoss and jBPM to implement design solutions that effectively address the issue of orchestrating long running activities.

Neo4j - The Benefits of Graph Databases

This presentation covers the use of graph databases as an optimal solution for data that is difficult to fit in static tables, rapidly evolving data or data that has a lot of optional attributes.

Realistic about Risk: Software development with Real Options

This session introduces Real Options and shows how it can help in running your project. Real Options is a decision-making process that can be used to manage risk.

Communication Flexibility Using Bindings

This article discusses the use of bindings on services and references (including the instance of non-configured bindings) as the means to implement SCA communications in a Web and SOA environment.

Writing DSLs in Groovy

After a short introduction to DSLs, Scott Davis plays with the keyboard showing how to approach the creation of a DSL by typing working snippets of Groovy code that get executed.

Scaling Agile with C/ALM (Collaborative Application Lifecycle Management)

IBM Rational and InfoQ present, Scaling Agile with C/ALM, an eBook showing organizations how to become “finely tuned software delivery machines” by enabling team integration and scaling.

Concurrent Programming with Microsoft F#

Amanda Laucher presents a real life enterprise application written in F#. She shows actual code snippets, explaining design decisions and suggesting how to use some of the F# constructs.