4 ms·
That is why Macros and creating your own DSL is so powerful :)
by baldfat 9y ago
That is why Macros and creating your own DSL is so powerful :)
- JohnBooty 9y agoThis is purely my opinion but after working in the Ruby world for a few years I've concluded that DSLs are harmful as all hell. A DSL is almost never as well-implemented as a "real" language, ala Ruby/Java/Haskell/whatever. This is to be expected, as orders of magnitude more engineering time are placed in those "real" languages. Specifically, DSLs tend to be very leaky abstractions. I always find myself needing to look at what's happening in the bowels of the library providing the DSL anyway; a DSL essentially just adds another level of indirection. Particularly for beginners, but also for more experienced coders, it can be difficult to tell where the language and its core libraries end and the DSL begins. If your DSL "foo" seamlessly adds the command "bar" to language "baz" and it's not working for me, where do I look for information? In "foo" or "baz?" The obvious example here is Ruby on Rails. Some may say that Rails is a poor example of a DSL. While that may be, it raises the question: are there better examples out there? Given that the goal of a DSL is to blend into the underlying language, I'm not sure how any implementation would avoid those pifalls. To me, the best case scenario is that DSLs generally save a moderate amount of typing in exchange for a considerable amount of cognitive overhead.
- lmm 9y agoA good DSL is just a library - or at least, there's no clear sharp line between them. Likewise, I think good programming looks a lot like creating a DSL (or rather a succession of them, with a tower of interpreters from the business logic at top level down to lower-level DSLs until you get to one that can be interpreted directly by the machine). The difference between a good DSL and a bad DSL is that a good DSL lets you reason about it the way you reason about normal, plain old code: you can factor out repeated function calls, inline constants that are only used in one place, and so on, and it will all just work the way you'd expect. A good DSL should just be plain old code, as should most of the language standard library, and then it doesn't really matter whether a given function is part of the language or a library. I've been very happy with the Scala DSL experience; I'd suggest something like https://github.com/http4s/rho https://github.com/http4s/rho as an example.
- davexunit 9y agoI don't think it's fair to judge DSLs (Embedded DSLs or EDSLs to be more precise) as a whole based on Ruby alone. I write Ruby at my day job and I think it's metaprogramming features are lacking. Languages like Clojure, Scheme, and Common Lisp are much better places to look. Designing languages is an inherent part of programming, but not being able to extend the syntax of your host language (as is the case in many languages) is very limiting. In the years I've spent writing ES5 JavaScript code, I've constantly wished there was a macro system I could use to stop writing this: (function($) { doSomeJQueryStuff(); })(jQuery) and instead write something like this, which is what I could do in any other sane lexically scoped language: let($ = jQuery) { doSomeJqueryStuff(); } Instead I had to wait for the language design gods to add similar syntax to ES6. I think any programmer should be able to put on their language designer hat and add some syntax if they want.
- flavio81 9y ago>Some may say that Rails is a poor example of a DSL. While that may be, it raises the question: are there better examples out there? You are understanding DSL as "ok, let's import this library that defines a DSL". In the Lisp world, one favored approach is to express the problem in the most natural way possible (i.e. like if describing the problem in english, or in any case, in your dsl language that best suits the problem.) Then, you use Lisp macros and implement this DSL. This has the side effect of making your program work, and thus, your problem to be solved. And, thus, the problem itself is specified in a high-level DSL, where it's more easy to understand and modify. Note, also, that on a Lisp-family language, creating a DSL is very easy, since metaprogramming is very very similar to regular programming. (In Lisp, metaprogramming is not some advanced topic; quite the opposite, is taught to beginners as well.) So, for example, if i want to create myself a library that outputs HTML, i define my DSL, which can be something like: (with-html-output (:html (:head (:title my-page-title)))) or perhaps (do-html-output (do-html-head :title my-page-title :includes js-include-list)) Then, later, i'll create the functions and macros that make my language work. This solves my problem. As you can see, anybody who knows about the problem domain of "let's do HTML output", will easily understand this DSL. In any case, if you are importing a library that defines a DSL, if the library is good, then by definition the DSL expresses the problem in the clearest way possible, and thus, it should be an easy library to use. Perhaps it has something to do with the syntax? In Lisp, the syntax is very uniform (s-expressions) while Ruby has a far greater variety of symbols and constructs.
- cujic9 9y ago> Note, also, that on a Lisp-family language, creating a DSL is very easy. I'd argue that this is a bug, not a feature. Yes, DSLs can make for elegant code, but it comes at a high cost in the form of a hidden dependency: the state of the DSL author's brain. In order for us to share a codebase with a DSL, I now need to understand your unique, high-level view of the problem, and be able to speak it fluently. And if your view of the problem is incorrect, I need to be able to hold two conflicting viewpoints in my head and find a way to resolve them. (Something that humans find quite difficult.)
- 9y ago