Kind of, except that a non-DSL API doesn't create any new syntax. Which means that you get to keep all sorts of quality-of-life tools like syntax highlighting and correctness checking in the editor, autoformatting, possibly some amount of linting, etc.
A few years ago I revisited Racket after a long hiatus, and that was maybe the biggest thing I noticed. I really don't like syntax macros as much as I did back in the day. Once I decide to use `define-syntax` I've then got to decide whether I also want to wade into dealing with also implementing a syntax colorer or an indenter as part of my #lang. And if I do decide to do that, then I've got a bunch more work, and am also probably committing to working in DrRacket (otherwise I'd rather stay in emacs) because that's the only editor that supports those features, and it just turns into a whole quagmire.
And it's arguably even worse outside of Racket, where I might have to implement a whole language server and editor plugin to accomplish the same.
Versus, if I can do what I need to do with a reasonably tidy API, then I can get those quality of life things without all the extra maintenance burden.
None of this was a big deal 20 years ago. My expectations were different back then, because I hadn't been spoiled by things like the language server protocol and everyone (finally) agreeing that autoformatting is a Good Thing.
Conversely, Ruby is often seen as facilitating DSL's, but none of it changes syntax, because the syntax as-is is flexible enough that redefining methods is sufficient. But everything still abides by the same syntactical rules.
The more orthogonal or flexible the language is, the less there tends to be a distinction between redefining syntactical elements and defining functions or methods.
Even without the new spiffs, I still don't see the point of DSLs. From where I sit, I see exactly zero problems where I think that new syntax is what I need to be able to write a solution.
I used to feel that way. I’m still not a convert, but now I’ve seen a lot more complexity papered over by a nice DSL.
Standard math syntax is a DSL. I understand math a lot more quickly than I understand the same thing written in 20 lines of code.
I think the language we use to express ourselves influence the quality of the product. If your language encapsulates complexity, then you can build more complicated things.
I’m not arguing in favor of specific (“pointless”) DSLs, but there’s a nice paper about making a video editing language in Racket [1] that makes a DSL seem pretty convincing.
The protocol buffer / grpc definition language is another great example of where a DSL can shine. Especially if you compare it to efforts to accomplish basically the same task using pre-existing languages, such as OpenAPI (JSON) and WCF (XML).
You could write DSLs for them, but you could just as easily do it within the existing syntax. Which is exactly how all the popular lisp implementations of OO, concurrency and type checking work in practice.
Many of them do use macros. But that's not about creating a special language; that's about moving expensive computations and checks that can be done statically to compile time where they belong.
Where, in a real program, `domain` would be defined in a "standard library of constructions" that you can just import and re-use in more complicated regexes.
Something like this can be implemented in any language with operator overloading, no DSL required. Without operator overloading, the syntax would be a bit more awkward, but still nicer than the current regexp madness.
I don't quite understand where regex gets its reputation from. I think that once you remember the meaning of the operators, it's not too bad. (And the concise syntax is actually very helpful.)
I get that the meaning of the operators is not clear unless you're already familiar with regex, but neither is the meaning of !, ?, %, &, |, ^, ~, &&, ||, <<, >>, *, //, &, ++ (prefix), ++ (postfix), and so on. You learn these because you need them once, and then they're burned into your mind forever. Regex was similar for me.
I think regex gets some of its hate from people writing painfully complex matchers. 99% of my day to day regex use is simpler string searches on the command line or in my editor. I’m really happy I took the time to learn the syntax (spent about a week on it around 15 years ago) because now it doesn’t get in my way.
Regex syntax helps you understand what a regex does, not necessarily why it does it.
You can't decompose it into parts, you can't give those parts human-friendly names, you can't re-use parts in other regexes, you can't (easily) write functions that return or manipulate regexes (like that "list with separator" function shown above).
There’s really nothing about this that couldn’t be expressed just as clearly in a more general API though, even in C, IMO. Building it into the syntax is a little weird to me.
Fair point, though I learned regexes a long time ago, so that they weren't on my "problems that I can solve with new syntax" list, but instead on the "syntax that's already there" list.
> Kind of, except that a non-DSL API doesn't create any new syntax.
Internal DSLs are always (by definition) valid code in the host language; external DSL, where parsing and interpretation or compilation to executable code for raw text code in the DSL are implemented in the host language, are all new syntax, but “languages that encourage making DSL” are usually ones that are favored for internal, not external, DSLs.
I think that "internal DSL" is what the grandparent poster meant by API, so I just went with that.
I think the internal/external terminology might be kind of outdated, anyway? I think this might be the first time I've encountered it in the wild in over 10 years.
> I think that "internal DSL" is what the grandparent poster meant by API, so I just went with that.
When people talk about REBOL/Red (or Ruby or Lisps) encouraging making DSLs, they are referring to internal DSLs. In Ruby, these are just APIs consisting of normal objects and methods, in Lisps they often involve macro calls, which may or may not correspond to what people mean by an API, and in REBOL/Red the design of the language is such that “normal” functions can do things that would take macros in Lisp.
An API creates its own ad hoc rules too. They just don't change the grammar.
In languages where the grammar is sufficiently flexible, the distinction all but disappears, but even in languages where the grammar is rigid and API's stand out like a sore thumb, the API itself still creates a new rule-set that you need to learn.
You can choose to not call that a new language all you want, but the cognitive load is still there.
An API (as people usually mean by it, anyway…) is really just a simple grammar for the creation and manipulation of objects in the system. Those objects still have types and properties just like any other object, but they tend to be implicit and unreliable. A good DSL is just a more abstract and implicitly verb-oriented API. For example, Lua DSLs can resemble something almost like a sort of typed or tagged DDL. Translating that into an “API” just adds more clumsy legwork to achieve the same outcome.
Agreed - I was tempted to make the same claim that it is still a grammar, but decided against it as I suspected it'd get in the way of making the point. You're 100% right you can write a grammar for an API as well, or can consider the API definition it self as creating a grammar.
This might be one of the rare times it's worth it. The C# team alread has the experience and tooling to maintain a language. Maintaining a DSL might be a reasonable choice for them.
It's rarely a good idea for app or library devs to make a similar decision.
Yes, this reminds me of meta-programming in languages like Python, it's useful if you want to create a framework like Django, but if you work on products, chances are good you should not use it.
There are plenty of places where it makes more sense to use DSLs (or where they’re flat-out required). SQL and regex both spring to mind. Pretty much any HTML templating language is simpler to use than concatenation a bunch of strings together. JSX is usually easier read than directly calling React functions directly. A line of a shell script can be much nicer (and more portable) than 20 lines of a more general purpose language.
Those are things that spring to mind that I think are unequivocally DSLs, but if you’re willing to consider markup languages as DSLs, the list could get a lot longer.
Most people think of DSLs as a language you can create within a language. All the things you named are either entire languages themselves like HTML, SQL, and the shell family, or formal extensions of existing languages like JSX. A DSL would be something you could create inside JS tagged literals or Ruby.
No, an API is a contract. Just like an object or a class or a structure is not a DSL.
None of these modify the syntax or keywords of the language used to implement them, and only objects and classes actually have the ability to override operators.
Just grouping things together in a particular order and giving the group a name does not make a DSL.