Half-Embedded DSLs

Domain Specific Languages (DSLs) come in two primary flavors: external or embedded. External DSLs have their own external tools – parsers, interpreters or compilers, optimizers, etc. – apart from any general purpose language. Embedded DSLs exist in context of a general purpose language such as JavaScript or Haskell. In practice, external DSLs tend to grow in power to cover various corner cases until they accidentally become poorly designed general purpose languages. Embedded DSLs can avoid this fate by providing escapes to the hosting language’s semantics. However, these escapes can also make it more difficult to port, reason about, optimize, serialize, or update the DSL code.

There is a sweet spot that lies between embedded and external.

For an external DSL, we are implicitly assuming a particular approach to code distribution, e.g. Alice sends Bob some DSL code, which is then parsed and interpreted by a program that Bob already possesses, which hopefully has a compatible version. This sweet spot is found by tweaking the code distribution model: Alice sends Bob some DSL code, and Alice also sends Bob the program to parse and interpret (and optimize) this code. Alice can then address corner cases by updating her interpreter, and further retains all the advantages of external DSLs.

In this case, the interpreter is sent using a common general purpose language or bytecode, and the client provides a simple API. If you’ve worked with many of JavaScript frameworks, you’ve probably encountered this pattern, with the DOM serving as the API. A script section doesn’t need to be JavaScript, and might be interpreted by other JavaScript code.

Of course, design at this sweet spot presents a few performance challenges.

First, those parsers/interpreters/compilers/optimizers can be relatively heavy – themselves having hundreds of kilobytes up to a few megabytes of code. Alice doesn’t want to send the full interpreter every time a web-app is loaded… and Bob, similarly, doesn’t want to parse and compile and link a big interpreter every time. If a DSL is popular across dozens of websites, Bob also doesn’t want to load dozens of copies to accommodate his tab addiction. We need a good way to cache and reuse the interpreter code, at which point Bob can afford to optimize it heavily and use it hundreds of times.

Second, we ideally want the DSL code itself to operate with near-native performance. This suggests we need some sort of just-in-time or dynamic compilation, i.e. such that we can compile a DSL by translating it into the host language or bytecode. People care about performance. It would undermine the use of DSLs if developers had to jump through hoops to squeeze excellent performance from them.

In conventional PLs, interpreters tend to become named packages, and dynamic compilation is relatively rare or awkward. So this approach to DSLs seems to be rare outside of JavaScript. And, unfortunately, JavaScript is not a great target language (e.g. with respect to concurrency, security, serialization and distribution of first-class functions), and conventional URLs are not very nice as cross-domain reusable modules for bulky interpreter code. A simple secure hash of the resource would be much better: acyclic, origin independent, no cache invalidation.

I believe we’d have much to gain by developing and promoting a bytecode where these half-embedded DSLs can thrive, ideally together with an Internet with services, databases, and browsers progammable in this manner. My Awelon Bytecode (ABC) is designed for this role. Of course, JavaScript has all the advantages of incumbency and will be exceedingly difficult to dethrone, despite its weaknesses.

This entry was posted in Language Design. Bookmark the permalink.

2 Responses to Half-Embedded DSLs

  1. Neo says:

    This article describes the problems of DSLs very well, as well as hinting to their solution:


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s