5 ms·
Ruby's metaprogramming features are a far cry from Scheme's hygienic macro system. By saying metaprogramming is an anti-pattern, we're saying that us lowly pro
by davexunit 11y ago
Ruby's metaprogramming features are a far cry from Scheme's hygienic macro system. By saying metaprogramming is an anti-pattern, we're saying that us lowly programmers ought not to put on our language designer hat and let the professionals take care of it. Without syntactic abstraction, we're at the mercy of the language designers and waiting for the new language version to include the new syntax we want. And what about the syntax we'd like to have that isn't so generalizable to be included in a core language implementation?
For example, it's great to finally have a 'let' form in JavaScript, but any one of us could've written it ages ago if there was a macro system, but instead we've been writing (function(x, y) { ... })(z, w) which is the ugly version of what 'let' essentially expands into.
I've written small embedded domain specific languages for coroutines and functional reactive programming. They are small bits of syntactic sugar that make talking about cooperative multi-tasking or values that change with time much more natural, and I didn't have to invent a whole new programming language to do it. A more well known example of an EDSL is miniKanren, a language for relational/logic programming embedded in Scheme.
PG's "beating the averages" essay argues that you should be using the most powerful language you can. The most powerful languages have macros. Good macros allow you to build up your programming language to be tailor fit to your problem domain. Let's not write off a powerful tool because it's possible to write bad code with it.
- vinceguidry 11y ago> By saying metaprogramming is an anti-pattern, we're saying that us lowly programmers ought not to put on our language designer hat and let the professionals take care of it. That's not what I'm saying at all. What I'm saying is that use it like the tool that it is, and clean it up when you're done with it. Responsible use, just like you should exercise with Scheme.
- davexunit 11y agoHmm, the tone of your post lead me to think that there was no responsible use for metaprogramming, since you actively work to remove it from your codebase. I don't think it's just a productivity hack, it's a long-term maintenance, comprehension assistant.
- jarcane 11y agoFor that matter, I actually have invented an entirely new programming language mostly with just Racket macros. It's an incredibly powerful tool for experimentation and research as well, something the PLT folks have been using to their advantage for some time now. I'm currently in the guts of several different candidates for building a basic Lisp on Risc OS, and it's really struck home just how much of a lowering of the barriers a really first-class metaprogramming system is when it comes to language development. Building everything from scratch takes time and often, a lot of repeat effort on stuff that's already been written a dozen times before. Macro systems, especially weapons-grade full-blown language development kits like what Racket can do, are a pretty hard thing to argue with on that front.
- agumonkey 11y agoDick Gabriel said in a podcast that late 70s language research was mostly lisp with macros. And when the PhD student was close to the finish line, he'd wrote a concrete syntax so it looked like a real-er thing.
- ggchappell 11y ago> By saying metaprogramming is an anti-pattern, we're saying that us lowly programmers ought not to put on our language designer hat and let the professionals take care of it. I don't agree. For example, most of us here would probably classify manual memory management as an anti-pattern. We're capable of doing it; we do it when we must. But we recognize that, most of the time, it's a bad idea. Perhaps vinceguidry is saying something similar about metaprogramming.
- current_call 11y agomost of us here would probably classify manual memory management as an anti-pattern Er, no?
- vinceguidry 11y agoAn anti-pattern is not a synonym for "bad code." Too many in this thread are making that mistake. A software pattern is a tool used intentionally to help better structure your classes. It's usually well-studied by people smarter than you are, the edge cases accounted for and documented. An anti-pattern is a solution you find yourself using unintentionally that you notice is causing you pain later on down the line. The first 10 times or so you just fix the pain, you don't start noticing it until instance 20 or so. If you were to study that anti-pattern, you could figure out why it's causing you pain, and maybe even solve the pain points and turn it into a real software pattern. If I'm doing exploratory programming that I don't expect to have to support or maintain, sure, I'll use all the power tools I can get my hands on to do cool shit with. But when I'm working on systems I don't care personally about, I want as little friction as possible between problem and solution. I don't want to have to look at a piece of code and wonder, "WTH is that doing again?" I notice myself having that reaction far more when there's metaprogramming involved than when there's not. It's not that there's no way to use metaprogramming effectively or maintainably. It's just that I have to think that much more carefully about proper separation of concerns, how the messages are passing, what happens when there's errors, stuff I don't have to think about when I'm doing it the boring way. When something goes wrong in boring Ruby, the backtrace is all I need to figure out what's going wrong. I've had the experience way too many times, of, over a dozen or so refactorings of a piece of metaprogramming I was too proud of to rip out, finally realizing that there was a bit of state I could have passed in a perfectly normal fashion that would have completely eliminated the need to, say, do dynamic class generation. Had I not been so hung up on my own brilliance, I could have saved myself hours of effort. Likewise, if you find yourself reaching for manual memory management, that is, rolling your own management structures rather than using one of the countless well-tested constructs available, without really understanding why, then you're probably overlooking some library you could use that would do exactly what you want it to do and handle all the myriad edge cases had you given it some thought. I would absolutely consider manual memory management an anti-pattern unless you're working in embedded environments or demoscene, and sometimes even then. C is way too mature for you to be reinventing things. Programmers are some of the most masochistic professionals I've ever met. They don't want to do things the easy way, easy seems to equate to stupid for them. You're not Linus Torvalds, the stakes just aren't that high. An .8kB in superfluous code loaded up in memory alongside the .2kB of the library you do need isn't going to kill you, only keep you sane. Don't make unnecessary work for yourself. Finish up early and go home and spend time with your kids.
- agumonkey 11y agoIt's funny, javascript had no standard library, and the prototype semantics meant you could override anything at the `evaluated` level. It was very convenient to be able to enhance base objects. I liked lisp/scheme macros right of the bat for their structural cleanness (as opposed to C-like macros of course) but seen in the js way, it makes you realize how much you can now override/extend in that system.