22 ms·
One submission in the past with lots of good discussions: https://news.ycombinator.com/item?id=18538123 https://news.ycombinator.com/item?id=18538123 | 734 poin
by capableweb 4y ago
One submission in the past with lots of good discussions: https://news.ycombinator.com/item?id=18538123 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.
- dgb23 4y agoAnd 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.
- matheusmoreira 4y agoI'm not familiar with clojure or its libraries. Can you post some examples of well designed interfaces?
- capableweb 4y agoIf 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/walkthrough.clj https://github.com/clojure/core.async/blob/master/examples/w... - https://github.com/weavejester/compojure https://github.com/weavejester/compojure - https://github.com/ptaoussanis/timbre https://github.com/ptaoussanis/timbre - https://github.com/krisajenkins/yesql 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.
- moomin 4y agoThe 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.
- capableweb 4y agoI 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/49fb078b834e64f63122e3a8ad3ddcd1f4485969/src/main/shadow/cljs/modern.cljc#L310-L326 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.
- moomin 4y agoYeah, 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.
- stingraycharles 4y agoAbsolutely, 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.
- bazoom42 4y agoTypeScript have multiple packages available which adds macros.
- capableweb 4y agoCare 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.
- bazoom42 4y agoFor example: https://github.com/GoogleFeud/ts-macros 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.
- lispm 4y ago> 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.
- Scarbutt 4y agoYour whole comments sounds like you are trying to get some kind of validation for using clojure.
- capableweb 4y agoThat'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?
- snarfy 4y agoIt's also true of Forth and derivatives.
- popcube 4y agoif just do not append core, the curse of lisp will go back...