Hacker News new | ask | show | jobs
by notacoward 1998 days ago
It seems to me that the main reason DSLs aren't more widely adopted is that any DSL will be unsupported by other tools developers consider more important. Your IDE won't have syntax highlighting and auto completion for it, and a lot of developers nowadays seem crippled without those. Linters and semantic checkers won't understand it. Nor will debuggers. There will be no mocking libraries or makefile rules for it. The list goes on and on.

These are problems that every new non-domain-specific language has to address. It's quite a lot, and most of it is pretty tedious compared to designing the language itself. So even those who try to create DSLs often skip most of the "extra" bits, and other developers learn to hate DSLs.

5 comments

There are three use cases for DSL to consider. They can be used as alternatives to:

  1. libraries for general-purpose languages
  2. general-puprose markup languages
  3. graphical user interfaces
Of those three, I'd say your complaint is a compelling criticism for the first use case, but not the other two.

Probably not coincidentally, the first one is also the only one where Turing completeness is almost certainly a requirement.

For the case of alternatives to general-purpose markup languages, I would present as exhibit A that the readability and tooling support for gRPC's *.proto files is far ahead of that of OpenAPI's JSON-based format. And that's not just down to popularity. Now that the language server protocol is so well supported, it's generally easier to get good tooling support for a homegrown DSL than it is a format that reuses an off-the-shelf markup language.

It's harder to find well-known examples for #3. All I can say is that, in my experience working on in-house software, I've seen that there are certain classes of problem where DSLs are generally more successful than GUI-based solutions. Usually these are situations where people need to manage complex and subtle configuration. In those situations, DSLs tend to be both less expensive to develop and maintain, and easier for end users to learn and use, than GUI-based solutions. A solution that uses a general-purpose markup language like XML or JSON may be cheaper to develop, but tends to be the worst possible option from an end-user perspective.

I think this is a great point, but I'd counter (disclaimer: I work on developer tools for a DSL).

It's a great time to create language tools. The language server/debug adapter protocols make it possible to develop a rich backend for your language of choice and a thin client to integrate into many editors, rather than extending a single editor/IDE platform. You don't really need to build an entire IDE to create a rich IDE experience, or tie that experience to a particular platform.

I'd also add that you can get really far without linters/static analysis tools. A DSL doesn't necessarily need them to be useful. That said, there are language agnostic linters you can use to add support for your own language.

I will say though that there needs to be richer/better language agnostic tools. There are a few for linting, debugging, static analysis, etc, but there's a need for things like auto formatting, CI/CD/general automation, build systems, and package managers. There are a many but it's tough to know which horse to pick.

> It's a great time to create language tools.

Absolutely. In fact, after I wrote that comment I started thinking about what could be done to make this easier. Language servers help a lot with some parts. Linters and checkers might be able to use something like that, if you're transpiling. Run standard tools on the target form, but with ways to tie results back to the original source. If we stick to a transpiling model, CI/CD integration might also be eased with a generic DSL adapter that just needs to know extensions and target language. It's now on my list of "maybe some time" projects now that I have a lot of spare time, but TBH it's not high in that list so I doubt I'll get to it.

I have my own ideas about making CI/CD for DSLs easier. I don't think transpiling is necessarily the right approach, since not every language has a valid transpilation targe (here's my bias showing - consider a hardware description language, there can't really be a transpilation target).

One of the problems in designing generic tools for language development is they have to be far more abstract than the author might realize at first. The notion of evaluation is a big one, as in what it means to evaluate a chunk of code, what its results are, its intermediate products, and when the evaluation takes place (is it compile time, run time, parse time, etc). I think the next generation of tools are going to inspect these subtleties a lot more than traditional tools, since it has a big impact on usage when languages have heavy macro or other compile/parse time evaluation.

Building a DSL on top of JetBrains MPS will give you most, if not all of that. You can distribute an IntelliJ plugin or even a standalone IDE.

https://www.jetbrains.com/mps/

Thanks, that looks interesting. AFAICT it only covers the editor/IDE parts, though, and that's not even close to "most" of what I mentioned. How does it help create linters and checkers? How does it ease integration with debuggers and build systems? Plus, you have to use JetBrains to get even that. Nothing against JetBrains, but that's not going to help at most companies which have already settled on other tools. It looks like a slightly easier way to create the core part of a DSL, but I'm not sure that solves the problem of the result being an "alien" thing that other developers will develop distaste for.
It uses a projectional editor, so there is only one way of "formatting" the code and no need for a linter. The typesystem is very powerful and allows a language engineer to create arbitrary checks on the language which are executed inside the IDE.

I have not tried building a debugger for a DSL in MPS, but it might be achievable, at least if you're targeting Java as a generated language.

Build integration is available for Maven and Gradle.

It's not crippling, it's annoying. I can code without an IDE just fine, I just don't want to.

It's too slow and you end up doing a lot of very repetitive and boring tasks. Modern IDEs, much like type systems, help you avoid whole class of errors.

Why type a method name, with the risk of typos, when with 3 keystrokes it's filled for you and provably correct.

Same for renaming operations, function/variable extraction, etc.

Also, code navigation. Large codebases are read a lot more than written. And code is not read like a book, it's more like traversing a graph. Do dataflow analysis, find usages, analyze hierarchies, etc.

In any sufficiently rich domain, necessary documentation and difficulty of use tends to approach that of a full language. The docs and tooling support scales much less well, often being provided only by a single team or organization. It's not a winning combination. With a general purpose language, you get all that mostly "for free".