|
The basic idea of a domain specific language (DSL) is a computer
language that's targeted to a particular kind of problem, rather
than a general purpose language that's aimed at any kind of
software problem. Domain specific languages have been talked
about, and used for almost as long as computing has been done. One community that uses DSLs a lot is the Unix community where
they are often referred to as little languages or mini languages.
(Eric Raymond provides a good discussion
of this tradition.) The most common unix-style approach is to
define a language syntax and then either use code generation to a
general purpose language, or write an interpreter for the DSL.
Unix has many tools that make this easier. I use the term External
DSL to refer to this kind of DSL. XML configuration files are
another common form of External DSL. 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. I have an extended example of both kinds of DSL in my recent
paper on Language
Workbenches. I also talk a lot more about the pros and cons of the
two styles and the recent development of language workbench tools in
the hope of making DSLs become more widespread. One of the tricky aspects of DSLs is that it can be difficult to
say what is and isn't a DSL. There is a very fuzzy DslBoundary
between internal DSLs and APIs; and between external DSLs and
general purpose programming languages.
I keep a note of DSL-oriented articles that appeal to me at
DslReadings.
Choosing Between Internal and External
The internal and external streams come to an interesting confluence in the figure
of PragDave. The
pragmatic programmers have long been fans of DSLs, primarily from
the Unix tradition (there is an excellent discussion in section 12
of The
Pragmatic Programmer - perhaps I should call that
Pragmaticum 12). In a thoughtful interview
Dave said that while he regularly uses code generation, he rarely
uses it programming in Ruby. I've always used the analogy of creating a DSL to help think
about building up a design - developing classes and methods with
an eye to making them be a DSL. As much as possible I do this
within the language I'm using, but if I can't I'm very ready to
switch to code generation. At ThoughtWorks we've used code
generation and similar techniques widely on our larger systems.
The point at which I pull the separate language DSL lever is
clearly different between languages. I never really felt the need
in Smalltalk to use a separate language, while it's quite common
in C++/Java/C#. As a result it certainly seems to me that certain languages are
more suited to internal DSL than others. Seeing lisp and
smalltalk I concluded that the more suitable languages were
minimalist ones with a single basic idea that's deeper and simpler
than traditional languages (function application for lisp, objects
and messages for smalltalk). But Ruby is more conventional and a
much bigger language than these two, yet is still suitable for
internal DSLs. So perhaps it's that languages need to have a well chosen
terseness. They need to make it easy to say common things and give
you nice syntax to avoid complex twists. Whatever it is I think
there's something very important here. I often find it hard to put
into words why it is I enjoy programming in Smalltalk or Ruby so
much more than in Java or C#. The most talked about reason is
static versus dynamic typing, but I've always felt that that
discussion misses the point. The friendliness towards internal
DSLs is much closer to the essence of the difference.
|