Sunday, March 18, 2007

Thoughts from a presentation on Domain Specific Languages

At the March meeting of the Tucson JUG, Warner Onstine gave a presentation on Domain Specific Languages (DSLs). I have to say that it was the most thought-provoking professional meeting that I've attended in a while.

Prior to the talk I was thinking that DSL was just a new name for an old idea. Jon Bentley wrote a CACM column on "Little Languages" in 1986 and that's what I'd pictured a DSL to be. At Warner's talk I learned that what I've thought of as a "little language" is known as an "external DSL". My understanding of the defining characteristic of an external DSL is that the syntax of the language is arbitrary and therefore a necessary component of an external DSL is a parser of some sort. Code written in an external DSL may be compiled, directly interpreted, translated to another language, etc.

I found the more interesting notion that Warner talked about to be that of an "internal DSL" (IDSL) . An IDSL has a "host language"; programs written in the internal DSL syntactically valid in the host language.

Warner put forth a "coffee example" in Java:
new Coffee("grande").type("latte").milk("soy").whip(false);
I understand that an API providing this sort of expressibility is said to be a "fluent interface". jMock uses this approach, too:
Ruby's grammar allows more flexibility than Java. Here's an example using ActiveRecord:
  create_table :products { |t|
t.column :pn, :string
t.column :descrip, :text
t.column :picture, :string
t.column :price, :decimal, :prec => 10, :scale => 2, :default => 0
It resembles DDL but it's just Ruby code.

rake, the Ruby-based build tool, takes the idea quite a bit further.

It's interesting to consider what attributes of a language facilitate internal DSLs. For example, being able to write method calls without parentheses in Ruby eliminates a lot of clutter. Ruby's notion of symbols allows for things like :decimal instead of "decimal", also reducing clutter. Ruby's blocks are considerable facilitators, too.

I believe that somebody at the meeting conjectured that it would be difficult have a very expressive IDSL in a language with static typing. Just now I found some interesting examples of IDSLs in statically typed functional languages, like Haskell. Perhaps the most interesting is Haskore, a Haskell IDSL for describing music.

It seems that ever since XML emerged there's a been growing phobia about using EDSLs. I've been dismayed by that because I hate clutter and it's hard to imagine anything more cluttered than XML. There have been tools like yacc for decades but Warner mentioned the idea of "language workbenches", which I'd describe as a next-generation tool for building EDSLs. One example is JetBrains MPS. Perhaps language workbenches will turn the tide of the industry's march toward XML-for-everything.

Regarding XML, I love this quote from Terence Parr, the creator of ANTLR: "Being an expert in XML is like being an expert in comma-separated values."

1 comment:

Chad Woolley said...

Rspec, a Behavior-Driven Development framework for Ruby, takes the DSL ideas pioneered by jMock even further, as facilitated by the Ruby language:


3.should be_an_instance_of(Fixnum) => 3.instance_of?(Fixnum) #passes

not_a_widget.should_not be_widgetable

my_hash.should have_key(:a)

You can write executable specs in a natural language. Rspec has built-in expectations, or can automatically turn your custom methods into expectations.