Are Project-Specific DSLs a Liability? [closed]

早过忘川 提交于 2019-12-04 07:15:58

There are of course arguments in favor of DSLs and against them, and there's of course a vague line between "a library" or "an API" and "a DSL". That part you've covered well in the question, so I'll avoid those subjective points and focus on just the question of whether they're a liability.

A good project to consider for this is Racket which puts language construction as its main feature. It's easy to slap up a language for any definition of "a language": DSL or not, made up from near scratch via an interpreter or (more commonly) done via macros that define the new language and possibly a parser for a different syntax. As a result, the Racket source tree has a bunch of languages -- some of them have fundamentally different execution semantics. Some examples:

  • Lazy Racket is what you'd expect the name to mean,

  • Typed Racket is a statically typed language,

  • Scribble is a language for writing documentation and other prose,

  • Slideshow is a language for writing ... slideshows,

  • RackLog/DataLog are languages that are even more different in both semantics and syntax.

In fact, making up languages is so easy in Racket, that you easily slap up a language even if it's something that fits a very limited use, or even just a single one. For example, we have such "small languages" that are used to create our web pages, decide which files are included in distributed installers, and many many more. See this tutorial for a description of how to come up with a language.

It's true that there's a fine line between a useful DSL that many people can use and one that only one person uses -- but still, the kind of abstractions that you can get when you define a language rather than a library are substantial, to the point that it's a useful concept even when it's a "one-man's language". One hard problem in this are is considering interoperability -- Racket allows each module to be written in it's own language, which brings up issues of what happens when several of these modules are supposed to talk to each other. For example, how does evaluation proceeds when there's interaction of functions in the lazy language and in the default one; or how does the typed make sure that it can interact with the default untyped language and still get the usual benefits of a statically typed language.

DSLs are widely used in Java. Just not 'internal' DSLs. Lisp has, unlike Java, several ways to alter the language syntax and semantics without writing a new external language. In Java, most DSLs are either external (often based on XML) or implemented with a pre-processor.

If you write a new programming language, also a domain-specific programming language, you need to:

  • specify it
  • document it
  • test it
  • make it robust
  • make it debuggable
  • make it efficient ... and more

Lisp is no magic bullet to do all that for you. What Lisp gives you is to include one or more DSLs directly into the language and it allows you to reuse or alter the Lisp facilities to implement parts of your new language.

Lisp had in its history a lot of languages implemented on top of it. Many of them were just research languages without too much effort to follow software engineering practices. Some of these languages had more effort put into them - for example because they were part of a product.

If you develop a language for your project, you need to make sure that you follow good software engineering practices and you have the resources to do so.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!