One submission in the past with lots of good discussions: https://news.ycombinator.com/item?id=18538123 | 734 points | 2018 | 281 comments

One of the main takeaways personally from this post, is the unique position Clojure (and other lisps) are in, where language additions can be done as libraries instead of changing the core of the language.

Other languages don't (always) have this possibility.

Taking TypeScript as one example. If 20% of users want to be able to do something in TypeScript that the language doesn't support, they either can try to get the change into the core language, or live without it (or fork it). If it changes, it'll change for everyone using TypeScript

But in Clojure (lisps in general), you don't have this restriction, so modifying the language for your own need, becomes a lot easier. Lots of work on Clojure is simply done in libraries, as it's possible and doesn't impact the core of the language, which everyone shares.

And it shows. Some of the more impressive and powerful libraries have incredibly ergonomic and clear interfaces, because the language let’s you simply do more with it.

I'm not familiar with clojure or its libraries. Can you post some examples of well designed interfaces?

If you're not familiar with lisps in general, it might be hard to grok the differences between lisp-macros (as used in Clojure) and "normal" macros you see in other (non-lisp [sans Elixir I think]) languages.

But, if you are familiar already, and just wanna see examples of neat macros that makes the API nicer than what a function could provide, here are a few:

- https://github.com/clojure/core.async/blob/master/examples/w...

- https://github.com/weavejester/compojure

- https://github.com/ptaoussanis/timbre

- https://github.com/krisajenkins/yesql

Furthermore, macros enables APIs like this, that would be impossible to have in JavaScript for example:

    (spy :info (* 5 4 3 2 1)) => 120
    
    %> 15-Jun-13 19:19:13 localhost INFO [my-app.core] - (* 5 4 3 2 1) => 120
`spy` here doesn't just print what the `` form is returning, but the form itself too. You wouldn't be able to achieve this without macros, as the evaluation of the `` form would happen before it gets passed to `spy`, so the initial form is already gone. Instead, a macro received the very code you pass into it, so you can print it, inspect it, rewrite it or whatever.