This is a great resource, especially because of its killer feature: user provided examples.
Some of the more powerful or special purpose utilities in Clojure are much easier to grasp by looking at some examples.
The only thing that is potentially better is a very well maintained wiki, like the MDN docs. But that’s a much bigger effort and only few wikis reach that level of quality.
Another cool thing about Clojure is that its core library and other parts of the language are quite small and understandable. I had quite a bit of fun reading and skimming the source, trying to understand things etc.
I agree. [Janet](https://janet-lang.org/) (which, coincidentally, has some superficial similarities to Clojure) has something similar at its [JanetDocs site](https://janetdocs.com/).
I did try to enter Clojure’s world multiple times (and succeeded to a degree), but I couldn’t put aside the ill-feeling while reading several well-regarded books on the language. It had such a narcissistic writing, looking down on every other language that I didn’t see in any other community. Maybe it is a lisp thing?
Nonetheless, fortunately it wasn’t enough to make me stop, because Clojure is indeed a fantastic language with a great community, but a bit less tribalism could benefit its writers.
> It had such a narcissistic writing, looking down on every other language that I didn’t see in any other community. Maybe it is a lisp thing?
Yes, it's a Lisp thing, but not without a reason.
Paul Graham explained this in "Beating the Averages"[1] more than two decades ago:
> Programmers get very attached to their favorite languages, and I don't want to hurt anyone's feelings, so to explain this point I'm going to use a hypothetical language called Blub. Blub falls right in the middle of the abstractness continuum. It is not the most powerful language, but it is more powerful than Cobol or machine language.
> And in fact, our hypothetical Blub programmer wouldn't use either of them. Of course he wouldn't program in machine language. That's what compilers are for. And as for Cobol, he doesn't know how anyone can get anything done with it. It doesn't even have x (Blub feature of your choice).
> As long as our hypothetical Blub programmer is looking down the power continuum, he knows he's looking down. Languages less powerful than Blub are obviously less powerful, because they're missing some feature he's used to. But when our hypothetical Blub programmer looks in the other direction, up the power continuum, he doesn't realize he's looking up. What he sees are merely weird languages. He probably considers them about equivalent in power to Blub, but with all this other hairy stuff thrown in as well. Blub is good enough for him, because he thinks in Blub.
> When we switch to the point of view of a programmer using any of the languages higher up the power continuum, however, we find that he in turn looks down upon Blub. How can you get anything done in Blub? It doesn't even have y.
> By induction, the only programmers in a position to see all the differences in power between the various languages are those who understand the most powerful one. (This is probably what Eric Raymond meant about Lisp making you a better programmer.) You can't trust the opinions of the others, because of the Blub paradox: they're satisfied with whatever language they happen to use, because it dictates the way they think about programs.
> I know this from my own experience, as a high school kid writing programs in Basic. That language didn't even support recursion. It's hard to imagine writing programs without using recursion, but I didn't miss it at the time. I thought in Basic. And I was a whiz at it. Master of all I surveyed.
Yeah I’m familiar with this blog post, but other than it being a huge fuel to this narcissistic tendency, it fails to explain to me any reason lisps would be that much above everything else.
Homoiconicity is a cool and elegant thing, but I think it has way too many things attributed to it. Plenty of languages have very strong macro capabilities, and while they may need a separate API for using it, this is hardly that big of a problem and in effect at that point they are just as good at everything as lisps are.
And we should not forget about the author’s (and apparently several other lisp-cultist’s) very own Blub paradox — they are often not familiar with strong type systems being able to prove the lack of several kinds of bugs, and I’m not just talking about the typical types, but about more advanced things like higher kinded types, effects, etc.
There is an entirely different aspect of languages dealing with new approaches to memory management like Rust, and newer ones having native support for arenas.
I'm not a fan of books like that because it doesn't teach you real-world usage. You can't be thrown into a standard clojure project repo after reading that book.
I used this book (+ others obviously) and I think it was the best one around so far, for me at least. It does contain exercises for you to solve specific problems, which is helpful, but otherwise 4clojure comes closest I guess.
By the way, what languages have books that makes you go from knowing zero to being able to jump into a standard X-language project repository after reading through the book? Usually it goes from "knowing nothing" -> "knowing a bit, solving small problems" -> "solving bigger problems, maybe contribute to small projects" -> "being able to contribute substantially" -> "being able to own a project and lead it", and I know of no (single) books that takes you across multiple steps. Usually books focuses on one of the steps.
> By the way, what languages have books that makes you go from knowing zero to being able to jump into a standard X-language project repository after reading through the book?
Totally agreed. Strangely Common Lisp is easier to start than clojure. Only once I can handle the system build up. Quickload, quick project etc. not clojure so far.
For me at least installing Leiningen was pretty straightforward. Just download the executable and it sets itself up. Setting up SBCL and Quicklisp was harder but not by a lot. What problems did you encounter setting up Clojure?
I am a huge fan of ClojureDocs, and in general community supported/open-to-submission style documentation systems, like MDN, and it was a godsend when I was first starting to learn Clojure. However, although I see this as a positive for the community, I also see it as a necessary outcome to the egregiously terrible official docs. I instead wish that the reality was that this wasn't necessary because the official docs were actually useful in any capacity. I look at Racket, Ruby, and Python as good examples of where the official docs work well enough to not really require a community supported version (yes, the docs quality vary between those three but they're pretty good and significantly better than the official Clojure docs).
I feel the same way! In fact, I wrote the first version of ClojureDocs (on rails) because people kept complaining on the mailing list about the official docs. It seemed like the best way to move community focus on to bigger and better things.
If only Rich Hickey could time machine himself back to when they were about to decide for the first time to integrate JavaScript with the browser and replace it with ClojureScript...
JavaScript was inspired by Scheme and Self. It’s a wolf in sheep’s clothing in that way. But yes, a Scheme would have solved so many issues and churn that we have to deal with. However people are scared by Lisps so there’s that.
I think it's partly due to: people like regular garden-variety arrays and hashmaps, and don't want to use car, cdr, cons. I like my array and hashmap literals.
One of the best things about PHP years ago was its documentation with user contributed comments. ClojureDocs is that for Clojure. The comments are gold.
I don't agree that Clojure suffers heavily from the Lisp curse. The prevailing paradigm in Clojure code is the almost exclusive use of the built-in data literals as function input/output (as opposed to using custom datatypes). For this reason, we don't really use frameworks as Clojure libraries are usually quite simple to glue together.
The main reasons why it is still fairly niche I would say are
- having to learn a new editor paradigm, e.g. paredit and/or parinfer
- functional programming
- people who think Java/JVM tech is icky
- an overall lack of promotion by Cognitect
Furthermore, you will need to both like the properties of Lisp as well as the the restrictions of functional programming on top of coexisting with Java on the JVM. This is a fantastic proposition to my ears, but it sounds horrible to some other people.
It seems really nice to work with but investing in a niche ecosystem that adds another layer of complexity on top of a tall stack is a hard sell for me personally
We build a product in Clojure that runs on the JVM and in the browser (https://kpow.io).
Clojure/Clojurescript gives us a language/toolset that works in both the front and back ends. In some cases we have we have code in a single source file (.cljc) that works in both the browser and on the JVM with no modification.
The feature that cross-environment functionality implements in a single source file is complex in some cases (e.g. a grammar / parser / interpreter for a subset of JQ).
Both the front and back end use the same core functions and same datastructures to implement the product. Data is moved between front/back via Transit (and encoding format for Clojure datastructures).
In my experience the reduction in complexity through the stack is staggering. Once you've learned Clojure that is..
My experience with guest languages for the last 30 years is exactly the opposite, not only one needs to master the platform, there is also the need to add on top extra tooling, libraries and the occasional dark magic debugging knowledge for the guest language to decipher how the compiler chose to represent the guest language to the platform infrastructure.
Hence why I only play with them to learn about new concepts, but always go back to what gets delived in the box for production code.
Indeed, my point applies to all of them, to anything !JavaScript on the browser, to anything !C#/F#/VB/C++/CLI on .NET, to anything !Objective-C/Swift/C++ on iOS,...
Basically whatever gets added on top of what is available when platform XYZ SDK (or equivalent), gets installed on a fresh new computer.
That's a good reason. You are working above Java, JavaScript and others, and that's often something that you need to be aware of and the details of those layers leak in a little.
It's still worth it for me personally, but I recon the additional challenge.
If you try babashka and nbb it won't feel as much of an extra layer, but they're both interpreted, so expect only Ruby like performance out of them. That said, it's a good way to get started if you don't want an extra layer under Clojure.
I actually did learn Clojure on the JVM. I read two and a half Clojure books, built a number of side projects, and I worked as a Java developer for a few years so the JVM wasn’t an issue. But even with all that, building a web app is far easier for me using Python/Flask, even with minimal experience with the language or framework.
And if I want to build a web service, I reach for go because it’s faster and the memory footprint is much smaller. I guess maybe if I was working on a super complex project that justified using Clojure to build elaborate abstractions, I would use it, but most of what I work on is pretty straightforward.
ClojureScript I’ve avoided because I keep anything frontend-related that I work on as dead simple as humanly possible to avoid churn.
And babashka seems neat too but I’m already comfortable with bash, and shellcheck works well.
It sucks but I just can’t seem to find a good use case for Clojure, even though I love the tooling and the language.
I don't know that there are good use cases, you just use what you want. For example I use Clojure and its variants for writing command lines, scripts, websites, backend services, Cron jobs, programming exercises/practice, and desktop applications.
Sometimes I use it for data analysis and visualization as well.
I use it at work and for personal stuff.
It's not that it has some awesome superior or full featured framework or feature for any one of those use cases, just that it's overall a language I like to use and which I have more fun with, and it's sufficient at everything you'd need to seriously use it for all those things. I prefer working interactively over a running program, I prefer the flexibility to extend language to my own needs with macros and higher order functions, I like the simplicity of working directly with data instead of ADTs or single use containers like Classes, I prefer structural editing for navigating and modifying source code, I prefer functional programming over OOP, I prefer immutable defaults and value semantics, and I prefer Clojure's well thought out core sequence manipulation functions.
My point is that Clojure is well rounded, there's a few things it's not good enough for, but those are rare, stuff like embedded systems, AAA games, high performance audio or video processing, raw number crunching, etc. For everything else Clojure is adequate, so it's just up to what you want to use, if you enjoy Clojure and it brings you joy, you can just use it, you don't need to find a perfect use case that it's uniquely best at.
It is a layer of protection against JS madness, and just a plainly better designed language. State management is much less verbose and easier to reason about.
But it is hard to justify outside of SPA and for “in between” use cases that for example Next solves very well.
The tooling is far from simplistic to setup and the available options can be overwhelming. Its all the pain of the JS stack but with less easily available help and tooling that produces less helpful error messages.
I think the tooling nowadays is pretty simple to setup, but the information out there doesn't speak to that new simple way, so everyone starting is following something that pushes them to outdated tooling.
Install Java:
brew tap homebrew/cask-versions
brew install --cask temurin17
Install Clojure:
brew install clojure/tools/clojure
Type `clj` at the command line and play with Clojure!
Now install VSCode and get the Calva plugin for Clojure from the marketplace.
That's it. You'll have autocompletion, jump to definition, code formatting and highlighting, linting, support for editor integrated REPL, debugger, etc.
Then you can run:
clojure -Ttools install io.github.seancorfield/deps-new '{:git/tag "v0.4.9"}' :as new
And now you can create new projects from various templates using:
clojure -Tnew app :name myusername/mynewapp
This creates a new basic application project for example. Open it in VSCode and you can connect a REPL to it and start working.
The errors are bad, but understandable in 99% of cases with a little experience (like 2-3 weeks).
And the stuff about the tooling is flat out wrong. The CLJS tooling is light years ahead of JS tooling in my experience. Maybe that was different back in the day, but shadow-cljs is seamless. Vastly superior to working with package.json/babelrc/postcssrc/webpack.config.js/etc/etc/etc
If you are going to compare modern CLJS tooling against JS - you should also compare against modern JS tooling like esbuild/vitejs which operate at light-speed.
There are some critical reasons for several people. Performance is one of them and lack of support for async/await is another. JS has also significantly become better in the last 5 years while Clojure has remained mostly static.
Some of the more powerful or special purpose utilities in Clojure are much easier to grasp by looking at some examples.
The only thing that is potentially better is a very well maintained wiki, like the MDN docs. But that’s a much bigger effort and only few wikis reach that level of quality.
Another cool thing about Clojure is that its core library and other parts of the language are quite small and understandable. I had quite a bit of fun reading and skimming the source, trying to understand things etc.