Creating DSLs in Java, Part 1: What is a domain-specific language?

Learn DSL concepts and where they're used in real-world programming

If you've ever written a makefile or designed a Web page with CSS, you've already encountered a DSL, or domain-specific language. DSLs are small, expressive programming languages custom designed for specific tasks. In this four-part series, Venkat Subramaniam introduces the concept of DSLs and eventually shows you how to build them using Java. In this first article, Venkat explains what a DSL is and defines the difference between an external DSL and an internal one. He then points out some DSLs you've likely been using for years, perhaps without even realizing it.

If you have been involved in writing or even just using applications, chances are that you've already encountered domain-specific languages, or DSLs -- even if you didn't realize it at the time. A keyword input file to an application that receives input data is a DSL. A configuration file is a DSL. A makefile is a DSL used to specify rules and dependencies for building an application. If you've written any of these, you've already taken your first steps to creating domain-specific languages.

The word language in the phrase may lead you to expect a DSL would use syntax to express certain semantics. Unlike a general-purpose language like Java, a DSL is fairly limited in scope and capabilities; as the name suggests, DSLs are keenly focused on a certain type of a problem or domain, and on expressing a narrow set of solutions within the context of that limited scope. And that's a good thing -- DSLs are simple and concise.

Okay, that's L; what about D and S?

The word domain in DSL refers to "an area or sphere of knowledge, influence, or activity." (For more information, refer to Domain-Driven Design by Eric Evans.) Focusing on a domain gives you a context -- a logical framework within which you can evolve models for an application.

The word specific in DSL gives you the bounded context. It helps you keep things relevant, focused, terse, and expressive.

Simplicity is critical to the success of a DSL. A person familiar with the language's domain must easily understand it. For example, if you're creating a DSL that actuaries will use to express business rules in the domain of insurance, you don't want them to spend a lot of time learning a difficult and complicated language. You want them to focus on expressing the details associated with insurance risks in a way that they can easily understand, discuss, evolve, and maintain. The DSL you create for them must be built on their vocabulary, the terms they use every day to communicate with their peers. You want them to use the syntax you provide, but it should seem to them that they're merely specifying some discrete rules. And they should be able to do so without getting the impression that they are really programming or even using some kind of a language.

Creating a good DSL is like cooking a nutritious meal; just like you want kids to eat vegetables without realizing and fussing over them, you want clients to use your DSL without worrying about its syntax.

Conciseness is another part of writing a good DSL, which means choosing syntax that is both terse and expressive. Terseness within reason makes your code easier to read and maintain. Expressiveness helps to promote communication, understanding, and speed. For instance, for someone who understands matrix multiplication, matrixA.multiply(matrixB); is less expressive and concise than matrixA * matrixB. The former involves calling functions and using parentheses, and includes an intimidating semicolon. The latter is already an expression that will be quite familiar.

1 2 3 4 Page 1
Page 1 of 4