I have only one thing to say here, to you and to all people who are opposed to macros and new languages in general: go learn some more (let's say 5) languages and then come back[1]. Don't bother before that.
Why? Because learning languages gets easier every time you do it. And it opens your eyes to languages' internal structure, the way languages are composed, which makes using given language effectively easier.
So now you know 5 or 8 languages and you discovered a few basic principles behind most of them and you understand how semantic constructs compose and you know about various syntactic representation of any given semantic statement (and the other way around, similar syntactic constructs having different meanings). And you come upon a macro, like the one in the example.
You don't know what it's doing - well, you just check the docs and then you know. It's as easy as learning what a function does, really. So what was learning those other languages for? It was just to reduce your fear of introducing new syntax for things. You won't think "oh, how dangerous this could be" but rather you just start using it, because you do it (change syntactical constructs you use) all the time when you switch between languages.
At this stage you can learn some Lisp. And write some real macros. And maybe try Nimrod, which has wonderful macros too. And maybe Rust, which I didn't try but I read good things about. After this you'll understand what macros are, how they are constructed and how they compose - and write many of your own - and then you look at the class example above and you instinctively[2] know that there has to be a syntax transformer which matches class keyword, a keyword and a block, and then there has to be another transformer, perhaps recursive (like in Scheme) or just iterating over the body (like in defmacro) and that all they do is to add some keywords here and there and a statement or two at the top of the block. In short - you know exactly what to look for and even docs are unneeded, you just take a quick look at a macro source and go on using it happily. Alternatively you can look at generated code and work out macro implementation from it easily, too.
I'm a happy user of LiveScript, and CoffeeScript before that. The only reason for not switching to JS with sweet.js is the fact that I would need to write a whole host of macros by myself, while in CS and especially LS they are already written. And of course modifying their grammar is not that hard either. Had I somehow been unable to use LiveScript, I'd use sweet.js for sure. What I'd implement? Probably some kind of "let" statement for sane scope management, a loop macro for iterating over custom collection classes (loop in CL, for/* in Racket, also in others), function currying (partial application) and maybe something like "with" context managers from Python would be among the first. There are many things which are better abstracted with syntax than with (for example) functions.
Would the language be JavaScript? Well, hard question, it would be a superset with underlying semantics intact, but it sure wouldn't "feel" like JS. But would that matter? Not at all - syntactic extensions would save me a ton of time and I'm used to many different syntaxes anyway. And I expect anyone who'd like to work with me to be able to pick up any language in reasonable time - the ability to pick up a few additional syntactic constructs on top of already known language is essentially the same thing, so I think such person would have no problems with it either.
Anyway, macros are good; using them is good; the only dangerous thing is having many people implement essentially the same macro over and over again, but I think this could be solved with a sane module system for macros which I read is already planned. There should be more languages rather than less; more exploration of different syntaxes and semantics for things, not less - and macros are one way of making this happen. And if you have problems with learning what a "class name body" does, then I can only refer you to the first paragraph.
[1] After I wrote this post I realized I could sound a bit rude. It was not my intention and I'm sorry if I offended anyone; while written generally, it's actually only a description of a road I personally traveled, so obviously YMMV.
[2] I know completely nothing about sweet.js in particular, so I'm completely just guessing.
I have written non-trivial programs in C, C++, Java, Javascript, ActionScript, PHP, Python, Haskell, Scheme, Go, and Sawzall, and also played around with prototypes or toy-quality programs in Common Lisp, Ocaml, Dylan, Erlang, Ruby, and Perl. I've written compilers, templating languages, desktop GUIs, web GUIs, mobile GUIs, parsers, machine-learning based data extractors, and distributed systems. I also lead a team, and I'm trying my hardest to bring a large, heavily used product into the modern era when it comes to web technologies. I was a huge fan of macros in college and the few years immediately afterwards. I've now done almost a complete 180 on them, and would encourage anyone I work with not to use them.
The reason is because I've come to understand that social factors trump technical factors nearly every time. The hardest part of writing a software system is almost never solving engineering challenges or writing code, it's communicating the solution to everyone who will have to touch it. Over a software system's lifetime, you will have to read code much more often than you will have to write code. Macros make writing code really easy and communicating everything about what it does, how it does it, and what invariants need to hold for it really hard. That's usually a poor trade-off for anything non-trivial.
I've found that working with a DSL structured around the problem domain improves communication and readability. Macros are a tool to allow you to easily implement these DSLs and have them fit nicely into the host language.
I actually like DSLs, but I think the right level of abstraction to develop them is by exposing the tokenizer, parser, AST, typesystem, semantic analyzer, and execution engine of the language as libraries in the language itself. Things like 'ast' and 'parser' in Python, package 'go' in Go, Clang for C++, etc. I've tried to fill this gap for HTML5 with Gumbo - it was initially designed to support a semantically-aware templating language in Google.
The reason I think DSLs are good but macros are bad is because DSLs make you think long and hard about the costs of implementing a new language. You have to pay for it up-front by writing a compiler and hooking it into your build system, even if you have help from the host language's libraries, and then you'll end up with something that's clearly a separate language and must be documented and learned separately. That cost makes it clear that creating a DSL is not something to do lightly, and you need a problem domain where there really are much higher-level abstractions that can't be captured by an existing programming language.
The problem with macros is that you can create a new language construct with a half dozen or so lines of code, use it in a few hundred places in the codebase, and now your maintainers have a few hundred problems.
But many DSLs can be implemented just as well without the use of macros.
This does not refute your point at all -- that macros can be very helpful when implementing DSLs -- just wanted to point out that macros are not a requirement for doing so.
Also, a DSL expressed using first-class entities will fit into and integrate with its host language more nicely.
While I completely agree with the second part of your comment, you didn't had to throw us your knowledge, skills and experience, it's anecdotal evidence and it weakened your point which was already strong enough.
I disagree completely, it's good to know from what position someone is arguing. And it's also interesting to see that someone with similar experience to mine came at completely different conclusion. So thanks nostrademons for the comment. While I disagree with most of what he wrote (I agree only with social factors trumping technical ones)it was still relevant as a whole.
Well, I think potentially made up (and practically uncheckable) experience and credentials don't make up for a trustworthy position, therefore they are completely unnecessary on a pseudonymous internet forum.
Unless your problem doesn't absolutely need them. It's considered bad style to use them when not absolutely necessary because they are much harder to reason about.
Macros can be dangerous in the 'give a man a hammer, everything looks like a nail' way. Like when some Python people went mental over meta classes using them everywhere they weren't needed.
I love macros (in lisp) but you shouldn't need to use them that much. They aren't always good.
> I love macros (in lisp) but you shouldn't need to use them that much. They aren't always good.
Isn't this true for almost everything? For example a while back there was this talk "Stop writing classes", where someone argued that you should just use functions for many simple cases (with nice examples etc).
Generally you should abstract on the level most suitable to the problem at hand. Some problems are best (for some value of "best") abstracted with a global var, others with a set of functions, others yet with hierarchy of classes. Syntactic abstraction is just another tool in your toolbox and it is very handy sometimes; of course it's not fit for every problem. But no one is going to do a "Stop writing macros" talk anytime soon, just because no one is writing macros - most languages lack them completely or have only silly string-oriented preprocessors, and even in languages that support them macros are feared and avoided.
I would just like to see macros go "mainstream" - if this means they'd be abused a bit (like classes/OOP now, for example) then I think I can live with it. Probably - it's quite possible I'd come to regret it very quickly :)
> I have only one thing to say here, to you and to all people who are opposed to macros and new languages in general: go learn some more (let's say 5) languages and then come back[1]. Don't bother before that.
You know nothing about sync, I presume, yet you assume he/she only knows very few languages because you don't agree. Don't do that.
I don't agree with sync, just pointing out that "go home and learn some programming first" is not a great argument.
I already apologized for this in the post. I realized this after writing it and it was late and I'd have to rewrite much of the post and so on. Essentially you should read all "you" in the post as directed at the me from X years back; it's not directed at sync or anyone else really. Sorry for the confusion.
it seems like you are validating @sync's concerns: you are saying it's ok to make up your own language if you have collected good patterns from other languages.
> if you have collected good patterns from other languages
Not at all - I think it's ok to invent languages, period. Little or huge, DSL or general, using established syntax or creating new ones - making them is good. The results can be bad (and frequently are), but that's to be expected of every process.
Knowing different languages just helps in seeing syntax for what it is: another level of abstraction, not a set of rules cast in stone. You can come at the same conclusion with a proper university class or with any number of other means - I mentioned learning languages just because that's what worked for me.
Why? Because learning languages gets easier every time you do it. And it opens your eyes to languages' internal structure, the way languages are composed, which makes using given language effectively easier.
So now you know 5 or 8 languages and you discovered a few basic principles behind most of them and you understand how semantic constructs compose and you know about various syntactic representation of any given semantic statement (and the other way around, similar syntactic constructs having different meanings). And you come upon a macro, like the one in the example.
You don't know what it's doing - well, you just check the docs and then you know. It's as easy as learning what a function does, really. So what was learning those other languages for? It was just to reduce your fear of introducing new syntax for things. You won't think "oh, how dangerous this could be" but rather you just start using it, because you do it (change syntactical constructs you use) all the time when you switch between languages.
At this stage you can learn some Lisp. And write some real macros. And maybe try Nimrod, which has wonderful macros too. And maybe Rust, which I didn't try but I read good things about. After this you'll understand what macros are, how they are constructed and how they compose - and write many of your own - and then you look at the class example above and you instinctively[2] know that there has to be a syntax transformer which matches class keyword, a keyword and a block, and then there has to be another transformer, perhaps recursive (like in Scheme) or just iterating over the body (like in defmacro) and that all they do is to add some keywords here and there and a statement or two at the top of the block. In short - you know exactly what to look for and even docs are unneeded, you just take a quick look at a macro source and go on using it happily. Alternatively you can look at generated code and work out macro implementation from it easily, too.
I'm a happy user of LiveScript, and CoffeeScript before that. The only reason for not switching to JS with sweet.js is the fact that I would need to write a whole host of macros by myself, while in CS and especially LS they are already written. And of course modifying their grammar is not that hard either. Had I somehow been unable to use LiveScript, I'd use sweet.js for sure. What I'd implement? Probably some kind of "let" statement for sane scope management, a loop macro for iterating over custom collection classes (loop in CL, for/* in Racket, also in others), function currying (partial application) and maybe something like "with" context managers from Python would be among the first. There are many things which are better abstracted with syntax than with (for example) functions.
Would the language be JavaScript? Well, hard question, it would be a superset with underlying semantics intact, but it sure wouldn't "feel" like JS. But would that matter? Not at all - syntactic extensions would save me a ton of time and I'm used to many different syntaxes anyway. And I expect anyone who'd like to work with me to be able to pick up any language in reasonable time - the ability to pick up a few additional syntactic constructs on top of already known language is essentially the same thing, so I think such person would have no problems with it either.
Anyway, macros are good; using them is good; the only dangerous thing is having many people implement essentially the same macro over and over again, but I think this could be solved with a sane module system for macros which I read is already planned. There should be more languages rather than less; more exploration of different syntaxes and semantics for things, not less - and macros are one way of making this happen. And if you have problems with learning what a "class name body" does, then I can only refer you to the first paragraph.
[1] After I wrote this post I realized I could sound a bit rude. It was not my intention and I'm sorry if I offended anyone; while written generally, it's actually only a description of a road I personally traveled, so obviously YMMV.
[2] I know completely nothing about sweet.js in particular, so I'm completely just guessing.