7 ms·
I don't think I've seen any convincing examples yet of how writing a new language or DSL is superior to the already-very-flexible idea of user-defined functions
by QuadrupleA 9y ago
I don't think I've seen any convincing examples yet of how writing a new language or DSL is superior to the already-very-flexible idea of user-defined functions, supported by almost all languages. Isn't a DSL just syntactic sugar in most cases?
Functions are verbs, usually named in problem domain terms, that can operate on a huge variety of nouns (data) also namable in the problem domain. So I don't buy that existing languages can't represent the problem domain, or force programmers to only do things in machine or traditional-language terms.
Don't want to be a spoilsport either, glad people are researching and experimenting with new approaches - just not sure I'm convinced yet the "make a DSL for everything" idea seems all that promising or different from what we already do as programmers.
- Volt 9y ago>Isn't a DSL just syntactic sugar in most cases? Maybe. But you probably have a programming language that you like to use when building Web apps, and another that you like to use when building command-line utilities. The differences aren't usually just the libraries available, but how easy it is to express certain solutions.
- 8ytecoder 9y agoNailed it. As you work longer on a project you'll realise patterns emerging. It's the same behavior repeated again and again. Take Rails for example, it is where it is because someone saw the patterns for a webapp and made a framework that conceptualizes it. It's something that's not appreciated very well. The concepts serve a vital purpose in organising your thinking in the problem domain.
- hyperion2010 9y agoIn a sense a DSL lets burried implicit knowledge become enshrined more formally (even if it is still implicit in a way) so that people don't keep making the same mistakes over and over because they are presented with tools where all the footguns haven't been safely dealt with. Consider how many people make the same mistakes over and over and over again because they go back to html, css, an js which give ZERO constraints on what one ought to do with them to make a useable website. Now imagine that we had been growing the language for writing websites so that new users literally could not write code that would footgun themselves into oblivion.
- nightski 9y agoYour examples amuse me because CSS & HTML are essentially DSLs :) I have to agree with the parent, well designed abstractions and functions in my opinion go 99% of the way towards providing the same benefits as a DSL without the additional complexity.
- hyperion2010 9y agoYes DSLs for constructing and styling a hypertext document, but as soon as we go beyond the simple document model of the web they are like handing someone a chainsaw and asking them to sculpt a chair that will be comfortable to sit in. Some people can do it with just the chainsaw and a lot of practice. However, in order to get most people to not damage themselves or the people who may someday try to sit in the chair, you have to create a robot to control the chainsaw. What you probably wanted was not a chainsaw attached to a robot, but rather a lathe, a plane, and some chisels, and some other hand tools.
- heavenlyblue 9y agoI believe what you’re trying to say is that every product has it’s own lifetime.
- hyperion2010 9y agoNot really lifetimes, even a stone hammer like one used 30k years ago is still useful in the right context (I still find html and css quite useful for what they were originally intended for). More that even very powerful tools have a niche or set of use cases where they excel, and outside that nice other tools are likely to be more empowering to their wielder.
- AlotOfReading 9y agoDSLs are a great solution where the problem domain is difficult to express in anything less. Matlab and Make are both good examples. My experience has been that they also bring enough documentation and maintenance burdens along with the flexibility that you should avoid them without a very good reason though.
- jononor 9y agoWhat does Matlab do that is not easy to express in say Python with sciencetific libraries? Setup of build rules is nice in Make, but if one accepts stringly-typedness one could reimplement something just as nice in say Python/Ruby/JS
- da_chicken 9y ago> Isn't a DSL just syntactic sugar in most cases? I don't think so. Maybe with things like LINQ, but in many cases a DSL lets you abstract things to such an extent that you get a new way of thinking about the problem. That's why DSLs are almost always very high level languages. SQL and regex are the obvious counterexamples, where you don't describe how to return the data you're looking for or how to store it on disk, you just describe that data and the language does the work for you. That's a completely different way of thinking about a problem compared to procedural logic. The languages allow you to describe very complex data in an explicit and unique manner, and in doing so allow you to abstract what the data is from how the data is maintained. Obviously, that can bite you if you structure your DB poorly, but on the flip side it allows people to learn how to use very complex descriptions of what are essentially abstract concepts instead of needing to know details that are extremely easy to screw up. Declarative programming is extremely powerful because of this, and it allows for extremely complex systems to be built on top of this new layer of abstraction. A shell is another counterexample where being "just" semantic sugar is really oversimplifying it. You're in a fixed context with a default function, so you get a lot of acceleration over having to spawn all those processes by hand. You're stripping out so much overhead code that you're into a new level of abstraction where -- unless you need to -- you don't think in terms of procedural logic. For a less straightforward answer, a generic programming language would be like a hex editor, whereas a DSL would be like PhotoShop (or even Paint). Sure, a hex editor can modify any type of file in any way, but the power of PhotoShop comes from all the power you get out of being domain specific. It's not just the additional built in functions the program gives you, it's also the manner in which the data are presented that allows you to see things which you simply would miss at the hex editor level. Here the abstraction is allowing you to see what the data actually represent instead of just seeing how the data exist in the computer.
- kerkeslager 9y agoLet's take one of your "obvious counterexamples": Exhibit A: [A-Za-z]\w*\(\d+(,\d+)*\) Exhibit B: cat(or(range("A","Z"), range("a", "z")), zero_or_more(alphanum()), "(", one_or_more(digit()), zero_or_more(cat(",", one_or_more(digit()))), ")") Exhibit A is absolutely syntactic sugar for Exhibit B. Regex is great if someone has already implemented a regex engine for you. But a key part of the post you're responding to is that it's talking about writing a DSL yourself. I can write the functions to run Exhibit B in probably 3 hours. I'd challenge you to write a reasonably language-integrated Regex engine in under 3 days, even assuming you have a good understanding of the domain. That difference in implementation time is going to take a while to pay off in composing actual regular expressions. And regular expressions are a very simple DSL. A more complex DSL would take longer.
- charlieflowers 9y agoI'm starting to look at it like this -- imagine writing an entire web app with Rails. Then, imagine re-writing it from scratch as a single page app, say with Angular. Then, imagine rewriting it _from scratch again_with React. (Obviously this is just a thought experiment, but an interesting one). _Something_ in your brain would remain the same through all of those projects. By discovering and articulating that something, you have arrived at more clarity on your domain. You've also made an asset that is more "fundamental" than the 3 web apps themselves. This asset would help you if you ever needed to port to other technologies in the future. You would also get incredible mileage out of this asset. It would represent the "skeletal structure" behind everything else you need to build, which means you'd have something like a, eh, 40% head start on most things. Maybe a 40% head start on automated tests, a 40% head start on validation code, etc. This would most likely lead you down the path of code generation, aka "everything is a compiler." It sounds promising and interesting, but I cannot "prove" the ROI. The time it would take to discover and articulate that "true core" could be significant (though in reality it wouldn't require rebuilding the same product 3 times). It seems primitive that we typically insist on articulating what we've understood about the domain in the same general purpose programming language that we intend to implement the solution in, and that we do so almost without being aware we're making that assumption.
- adjkant 9y agoI'm taking a class with the first author of this paper known as "Hack Your Own Language", where we read the draft of this paper as our first assignment. While I won't do it full justice I'm sure, I'll try to detail some advantages, though not all of them: 1. You can override built-in language features to better suit the domain of your problem. 2. You can control scope and evaluation of variables. While they often have good defaults, there are cases where you want to override them. 3. You could easily add partial or full typing as you desire to a language. Not runtime typing, but compile time with proper error messaging, and it will be a heck of a lot easier than hand rolling it trying to do it with functions. 4. You can change the very shape of the syntax. Imagine specifying a graph with only identifiers and ascii arrows and just listing them out, then performing DFS. No more Node/Edge class structures, you just work at the abstract level. That applies to any domain. If you're working with functions, you can't change the syntax of the language, which leads to very awkward code in some cases. The graph language: http://www.ccs.neu.edu/home/matthias/4620-s18/network-syn-lang.rkt http://www.ccs.neu.edu/home/matthias/4620-s18/network-syn-la... The graph language sample program: http://www.ccs.neu.edu/home/matthias/4620-s18/network-syn-lang-client.rkt http://www.ccs.neu.edu/home/matthias/4620-s18/network-syn-la... The language is simple, but as is the point, can be extended by anyone. That's powerful.
- fmap 9y agoLet's say a language A is syntactic sugar over a language B if A can be translated to B by macro expansion. In that case, if B is sufficiently expressive, e.g., has first class functions, then in many cases A will be syntactic sugar over B. On the other hand, there are many language features that are orthogonal to first class functions, for which the translation is no less complicated than the frontend of most compilers. For example: - Delimited continuations - Related to this, algebraic effects and handlers. - Implicit types. - Join patterns for concurrency. - Linear/Affine ressource management. - Related to this, type state and session types. - Probabilisitic programming. - Differential programming. And many more. The point is that you do not want a language that includes all of these extensions at the same time, since many are mutually exclusive. For example, differential programming does not mix with state or first-class functions. Linear types ensure safe ressource management, but you need an escape hatch both for efficiency and your sanity. Algebraic effects or delimited continuations in a language which already has imperative features will lead to very fun bugs as soon as someone unfamiliar with the language implementation tries to mix the two features. On the other hand, for every single example in this list I can point to an application domain where the additional expressivity is beneficial. E.g., delimited continuations are extremely nice when implementing some complicated backtracking search. A DSL with (pure functions and) first class support for delimited continuations can express such a search function very naturally and later on - in the compiler for the DSL - we can decide how to implement this feature. This allows for additional optimizations, which would otherwise be implemented in an ad-hoc manner. For example, several linear return continuations can be implemented by having several return addresses and stack pointers and restoring one of them, rather than using a cactus stack. Another example, rarely used return continuations can be tracked out of line as in "zero-cost exception handling". Mixing these implementation details with the implementation of your search function is just a bad idea, since they are orthogonal to the problem you actually want to solve. And, as we all know, mixing continuations into an existing imperative language just gives continuations a bad name, which is precisely why you want a DSL. :)
- marvy 9y agoThank you for writing this. I wanted to say something like this yesterday, but couldn't find the words and decided to wait for today to try. But I would have never put it this well even if I spent a year.