Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Building Domain Specific Languages in C#, Part 2 : Page 3

Building fluent programmatic interfaces lets users make calls in natural ways similar to speech.


advertisement

Fluency in Dynamic Languages

Building fluent interfaces becomes easier when you move to more dynamic languages. While type safety helps the compiler and tools like Visual Studio work, it interferes with building really flexible APIs. To that end, this section shows the same examples in a really dynamic language on the CLR: IronRuby. Ruby is often used to build DSLs because its syntax is so flexible and because it has powerful features that go beyond C#, such as true open classes.

IronRuby

In Ruby (and IronRuby), you don't have to use extension methods to add new behaviors to classes (either the built-in ones or your own). You can reopen the class and add new behaviors directly. For example, this snippet shows the Ruby code that adds the weight units gram and pound to all numbers (encompassing both integers and floating point numbers):

Ruby is older than Java! Ruby was developed in Japan by Yukihiro "matz" Matsumoto and released in 1995. It has slowly grown in stature, mostly because of the Ruby on Rails web framework.

class Numeric def gram self end alias_method :grams, :gram def pound self * 453.59237 end alias_method :pounds, :pound alias_method :lb, :pound alias_method :lbs, :pound end

In Ruby, the Numeric class is the superclass of all numbers, meaning that you can add the new methods to a single location. In Ruby, defining a class for a class that's already in the class path reopens the class for modifications—meaning you can add new behavior to classes without the formality of special types of classes and methods required in .NET. Ruby also includes the powerful alias_method mechanism, allowing you to easily create additional names for new methods.

The of method is similarly simple in Ruby, as shown here:

class Numeric def of(name) ingredient = Ingredient.new(name) ingredient.quantity = self return ingredient end end

Here, the of method doesn't have to worry about types because Ruby is entirely dynamically typed. To see this fluent interface in action, the following code shows an appropriate unit test:



def test_ingredient expected = Ingredient.new("Test") expected.quantity = 42 actual = 42.grams.of "Test" assert_equal(expected.name, actual.name) assert_equal(expected.quantity, actual.quantity) end

Ruby's flexible syntax (note that parenthesis are optional, adding to the fluency of the interface), true open classes, and dynamic typing make it a good choice for this style of DSL. All these examples run in the current version of IronRuby, so now is a good time to check it out.

Comparing Open Classes to Extension Methods

Let me make one last important distinction between the C# and Ruby examples. C# uses extension methods to add methods to the built-in types, while Ruby uses open classes. So what is the difference?

Extension methods add capabilities to existing classes. When resolving a method call, the CLR first checks to see if the method exists on the original class. If it doesn't, it checks to see if there is an extension method with the appropriate signature. If it finds one, it calls that method, passing the object instance as the first parameter.

Open classes are a much more powerful mechanism. When you reopen a class, you can do whatever you like: add new methods, override existing methods, and even delete methods programmatically. Using extension methods, you can only add new methods. So, open classes give you full access to the class definition, allowing you to make more far-reaching changes. Of course, with any powerful mechanism, you must choose when to wield that power. With Ruby, like any dynamic language, testing isn't optional!

The changes made to C# to make LINQ possible make it easy to build your own fluent interfaces. One of the goals of a fluent interface is readability. The ability to change core classes (such as the numeric classes) make the code much more readable because you can use the numeric argument as the entry point to the expression, rather than send it as a parameter. Why does that make a difference? Supporting syntax that's similar to the way people think makes it easier for non-developers to read code—because it looks similar to the way they would write or say it. Readability matters; leveraging that is one of the goals of DSLs (and fluent interfaces).



Neal Ford is software architect and meme wrangler at ThoughtWorks, a global IT consultancy with an exclusive focus on end-to-end software development and delivery of large-scale enterprise applications. He has also designed and developed instructional materials, magazine articles, courseware, video/DVD presentations, and is author and/or editor of five books, spanning a variety of technologies. He is an internationally acclaimed speaker, having spoken at over 100 developer conferences worldwide, and delivered more than 600 talks. Check out Neal's web site for more information.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date