Generalized Macros
&gt; Right, but the complete argument isn&#x27;t &quot;there are other ways to do this&quot;, the argument is &quot;there are other ways to do this, and nearly every one of them is less error-prone&quot;.<p>I feel like there&#x27;s such a wide variety of things that you could be trying to do with macros that this <i>definitely</i> true a lot of the time.<p>&gt; The same is true for popular libraries and whatnot that ship with the language, which is why I&#x27;m not particularly concerned about &quot;defn&quot; or &quot;for&quot; are macros. Those are macros in most implementations, I&#x27;m aware, but they&#x27;re really-well-tested macros because pretty much every Lisp developer to ever write a significant amount of Lisp has tested them. &quot;defn&quot; and &quot;for&quot; aren&#x27;t broken.<p>So I&#x27;d argue for this differently: defn and for and other pervasive macros aren&#x27;t safe because they&#x27;re well-tested, they&#x27;re safe because they&#x27;re <i>trivial</i>. You know that (defn ...) is short for (def (fn ...)). You know exactly the code that that macro expands to. And you can choose to type (def (fn ...)), or you can choose to type (defn ...). Same with short-circuiting &quot;and&quot;, or &quot;for&quot;, or &quot;+=&quot;, or whatever.<p>It sounds like you&#x27;re mostly talking about complex, hairy macros -- macros where you <i>don&#x27;t</i> know exactly what code they expand to. But I dunno, the fact that macros <i>can</i> create monstrosities doesn&#x27;t mean that you should have to type (def (fn ...)). It&#x27;s a feature with an extremely broad scope, and can definitely be mis-used.<p>&gt; I&#x27;ll point out that JavaScript already had async callbacks and promises (implemented as a library) when async&#x2F;await was added as a third way to do basically the same thing, resulting in JS codebases that now have half-baked glue to make the three ways work together. I&#x27;m not sure anybody was waiting for async&#x2F;await to do anything that couldn&#x27;t already be done, and the churn of reimplementing working code to use a new feature didn&#x27;t do anyone much good. But that&#x27;s sort of a tangent.<p>This is a very good point. Destructuring assignment, maybe? Arrow functions? I think we agree that <i>some</i> language features are good additions, even if I picked a bad example :)<p>&gt; Codebases that use extensive macros to create DSLs eventually become write-only. The power and readability you see in toy examples and in the short run in your own code, rarely plays out in the long run, and when it does play out it&#x27;s because of extensive testing and work--a lot more work than Bob and I have the bandwidth for.<p>I dunno! I can certainly see how an extensive macro-based DSL could degrade to something write-only.<p>I don&#x27;t know when the long run starts, but my experience with macros is that they&#x27;re just a huge productivity benefit that I wouldn&#x27;t want to give up. I haven&#x27;t seen a codebase degrade into an idiosyncratic mess -- perhaps, in part, because there&#x27;s a lot more friction to writing macros in OCaml than in Clojure, so macros are only used where they provide a substantial and obvious benefit. Or perhaps it&#x27;s that typechecking makes it much harder to write poorly-behaved macros. Or perhaps I just got lucky with my cubicle assignment :)