Hacker News new | past | comments | ask | show | jobs | submit login

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.




The thing is, it’s technically present, but culture is another matter. I maintain a Clojure project that ran using a number of interesting and convenient macros. In practice, it made things harder for people to read and was unidiomatic. If you want anyone else to use or modify your code, you’d better stick with Hickey’s vision.


Absolutely, and this is being completely ignored in the whole discussion. We’re utterly dependent upon Clojure “core” for anything to become idiomatic; saying that it’s possible to make anything outside of core and do your own thing is about as productive as saying “just fork it” about opensource projects.

I think that this post by Rich Hickey actually made me completely lose faith in Clojure’s stewardship after about 5 years. It basically signalled very strongly “we’re not interested in listening to the community”, which is fine, but that doesn’t align very well with how long-lived, successful opensource projects are managed.

And I say all this as someone who was very actively involved in some of Clojure’s largest opensource projects.


I just picked up clojure as a hobby project outside of work and I’m enjoying the language in general so far. I have to say that reading this rant gives me a bit of doubt about continuing.

I actually agree with most of what this guy is saying, but the delivery is not good.


Clojure, the language, and Rich Hickey, the vision, have had a tremendous impact on my programming career. Transformations of data as the primary building block for writing code was such an enlightenment. I absolutely encourage you to continue your endeavor of learning Clojure, as it’s almost guaranteed to be a net positive.

It’s just the stewardship of the language that is my biggest problem. It’s very anti-community (as evidenced by this rant), and in general there is a tendency of “elitist” mentality the more you get into the core community.

If you’re able to ignore all that, and just do your own thing, you’ll be fine.


Well, I managed it with the Emacs community, so I guess I can do the same here lol.


It’s an interesting road, and I like Clojure plenty, but ultimately it’s a cul-de-sac. And the reason it’s a cul-de-sac is pretty heavily laid out by the original post.


I don't know, the community in general tend to use macros that are well written. I keep seeing core.async being used (`go`) in Clojure projects, and also various macros for writing HTTP servers (compojure being a popular one which main code interface is a macro `defroutes`).

ClojureScript projects also routinely add support for making asynchronous code look synchronous (like `async/await` in vanilla JavaScript) via macros. shadow-cljs's `js-await` being one of the well-written ones: https://github.com/thheller/shadow-cljs/blob/49fb078b834e64f...

Usage:

    (defn my-async-fn [foo]
      (js-await [the-result (promise-producing-call foo)]
        (doing-something-with-the-result the-result)
        (catch failure
          (prn [:oh-oh failure])))
I'd say if adding a macro makes things harder to understand, you probably need to re-evaluate if you really should have a macro here, or the interface of the macro.


Yeah, there’s a couple of widely understood idioms like global static configuration and adding async/await. But the macros I’m talking about were very simple, well-defined things that exist in other languages. They were just unfamiliar.

In any event, they’re ripped out now. But ultimately macros offer a lot more in theory than in practice.


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.


TypeScript have multiple packages available which adds macros.


Care to link some of those? Are they macros as in C-macros or macros as in Lisp-macros?

Macros in C-like languages (like JavaScript or TypeScript) tends to be relatively basic text substitution macros, while in lisp they are part of the core language, and you construct macros just like you construct normal code.


For example: https://github.com/GoogleFeud/ts-macros

> while in lisp they are part of the core language

The power of the typescript toolchain is that a macro framework like ts-macros can be a package and doesnt have to be part of the core language.

If 20% of users want to be able to do something in a Lisp that the built-in macro system 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 that lisp. But in Typescript, you don't have this restriction, so modifying the language for your own need, becomes a lot easier. Lots of work on Typescript and Javascript is simply done in packages, as it's possible and doesn't impact the core of the language, which everyone shares.


> The power of the typescript toolchain is that a macro framework like ts-macros can be a package and doesnt have to be part of the core language.

Lisp can do the same, but macros are so central, that everyone uses it including the core of the language itself and anything written on top. It's not optional, since syntactic meta-programming is one of the core features of Lisp.


It's also true of Forth and derivatives.


if just do not append core, the curse of lisp will go back...


Your whole comments sounds like you are trying to get some kind of validation for using clojure.


That's strange. Being able to professionally work in Clojure for the last ~6 years or so is enough validation for me that Clojure is the right choice (for me).

Does my comment came across like that because I point out benefits from using Clojure, or what makes you say that?




Consider applying for YC's Summer 2025 batch! Applications are open till May 13

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: