linpengcheng: linpengcheng: Macros are suitable for language extensions, and application-level development is best not to use them.

I agree with you. Data abstractions are better when they can do, and you should favor them always.

My use cases for macros are in fact language extension use cases. And our macros are never application specific. They live in seperate packages, which are used by different applications.

Like the clj->java and java->clj macros to go from object to clj and back. Without extending the Clojure semantics, such a conversion is many more lines of code, and much harder to read, and easier to accidentally make a mistake.

Or I have a try/catch extension macro that allows multiple exceptions to be caught. Again, when dealing with Clojure only, you can branch your catch code on ex-data, but when dealing with a lot of Java exceptions, such a macro does improve code quality and readability. Otherwise you’d need to have a cond clause on exception type within your catch block.

In most cases, you can think of macros as code generation functions. Every piece of code that is repetitive and verbose adds extra potential for typos, or mistakes when writing it, and increases the burden to read it, by adding a lot of white noise. A macro can be useful in such case, at least in my humble opinion. That’s the case for my clj->java macro

Other times, you want to extend an existing macro, like my extended multi-clause try/catch. Or my extension to spec, or multi-clause when-let (https://dev.clojure.org/jira/browse/CLJ-2213).

So, I think you point out a great point, you really shouldn’t have application specific macros, I’m not sure I can think of a good reason too, in such case, it feels data or functions or something else can probably be used more effectively. But, it does come in handy to be able to extend Clojure sometimes, and the extensions can help you more effectively build applications.

I think there are language extensions that, if standardized into Clojure core, requires a much more careful process, because you commit to new patterns that can never be changed ever. And so, until you know there are no edge cases, or better patterns, or inherent flaws with the pattern, it probably shouldn’t be made standard. But, on a team, these burden are reduced. A team can more easilly adopt new patterns even if they have some flaws, its easier to be aware of them and work around them, or pivot away from a pattern that didn’t work out as well as it should have. Or, within the context that the team uses the pattern, those flaws might not matter, and thus the pattern is a net positive, but in arbitrary context it wouldn’t. For all these reasons, I believe its a great strength of Lisps to allow teams to develop their own extensions.