It occurred to me this morning that I should learn Clojure instead of Rust for non-lowlevel code because Clojure solves the same problems Rust solves in a much simpler way. I'm a fan of Clojure author Rich Hickey's "Simple Made Easy" talk but otherwise don't know either language in detail and need to do more research.
As an anecdote, about a year ago I realized I was not having that much fun learning rust. Randomly landed on clojure instead and have absolutely loved it.
Particularly as a noob, babashka is SUCH a good way to learn the language. I’ve written myself all sorts of fun utilities with babashka and have learned so much clojure along the way. Even got my coworkers to use my bb scripts!
The Clojure (or any Lisp) journey is very different, not because of the language per se, but because of the developer experience.
In Clojure, there's no appreciable compilation time.
During my work week I barely, if ever, restart the application I'm working on: I'm working inside of it via a REPL connection.
It's an entirely different ball game and if you just compare language features you are missing out on an incredible interactive coding experience.
> Clojure solves the same problems Rust solves in a much simpler way
I'm curious about that, can you elaborate? I'm a beginner in Clojure and I only know a few concepts about Rust, but it seems to me that they solve (at least, currently) very different problems...
I only saw Rust being used in places where C or C++ would be used in the past (Linux kernel, CLI apps, desktop apps), while I only saw Clojure being used as a modern and functional Java and JS replacement.
Not to mention how different they are as languages (static vs dynamic typing, native vs jvm, borrow checker vs garbage collection)
The main problem that Rust tries to solve, and that functional programming (which Clojure heavily leans into) solves, is avoiding shared mutable state, which leads to data races and (potentially subtly) wrong concurrent programs. Functional programming avoids shared mutable state by avoiding mutable state. Operations are only represented as transformations instead of mutations. Other languages like Erlang / Elixir use message passing techniques like the Actor Model to avoid shared mutability. Instead of avoiding mutability, like in functional programming, in the Actor Model you avoid sharing, by instead sending messages around.
Rust is interesting because it solves the problem of shared mutable state, while allowing sharing, and allowing mutability, just not at the same time. State can be mutated until it is shared. While it is shared, it cannot be mutated. This is the goal of the ownership system in Rust.
One thing that jumped out at me is you don't need Rust's borrow checker to prevent thread race conditions because data in Clojure is immutable. That's a huge simplification over Rust. What I hear mostly about Rust is complaints about the borrow checker. I wrote a simple Rust utility and found it frustrating. But again, don't take my word for it because I don't know either language.
As someone who has gone deep into both functional programming (with Elixir, Clojure, and Scala) and also Rust, they solve the same problem in different ways with different tradeoffs.
The problem is that shared mutable state is incredibly hard to get correct, especially when concurrency enters the picture.
Elixir and Clojure sidestep the problem by making copying data so cheap that instead of sharing references to mutable data, you make all data immutable and copy it whenever you want to change it in some way. (Which is a classic technique: don’t like the problem? Solve a different problem that sidesteps the original problem in a creative way)
So you have a lot of functions of roughly the shape `f -> f` (return a new thing) instead of `f -> ()` (mutate a thing in place).
This possible at all by the clever use of some novel data immutable structures like HAMTs that are able to approximate the performance of traditional mutable data structures like hashmaps or arrays while presenting an immutable API.
As it turns out, this is a much easier programming model for most of us to get correct in practice (especially in the presence of concurrency) than sharing mutable state in an imperative programming language like C or Java or Python.
The tradeoff is that the immutable functional data structures actually do have a some performance overhead. In most domains it's not large enough to matter, but in some domains it is, and in those domains you really do need mutable state to eek out that last bit of performance.
Which is where Rust comes in.
In Rust's model, data can either mutable or shared, but not both at the same time. The Rust compiler computes the lifetimes of data throughout your program to ensure that this invariant is upheld, so mutable data is not shared, and shared data is not mutated.
The downside of this is that you have to internalize these rules and program to them. They can be tough to learn and tough to program with even after you have learned them, though it does get much easier with experience, I will say.
The upside of Rust's model is that you can have your cake and eat it too: you can keep the high performance ceiling of a true mutable data model while maintaining memory and resource safety.
In short, you can think of Clojure/Elixir as sidestepping the shared mutability problem at the cost of some runtime performance (though again in practice it is smaller than you would think), and Rust as tackling the shared mutability problem head on by transferring the cost of solving the problem to a more complicated compiler and a harder-to-learn programming model.
These are just my opinions having used both Rust and the immutable data functional programming stuff in anger. I'm not trying to present one as being better than the other, the key point is that they're both better than what came before.
It's worth noting that there's several implementations of persistent/immutable/functional data structures for Rust already, and a few basic "building blocks" (namely std::borrow::Cow, noted for its bovine superpowers) are even in the Rust standard library. It's possible that we'll see more of them standardized in the future if a case can be made that they're useful and a consensus is reached wrt. some kind of minimally viable APIs.
My read today is that the advantage of Rust over C/C++ is that the compiler enforces the rules, where in C/C++ you'd have to use a static source code analyzer to find omissions. Since Clojure uses Software Transactional Memory and Persistant Data Structures to only make copies of updated shared data structures, it seems like it could actually be faster than Rust/C/C++ depending on how efficient the copy is. I may have it wrong but it sure is interesting...
That’s my take after using Rust for half a decade. The type system is very powerful and can encode logic in types in a way that’s impossible in most other languages, which is how the borrow checker works (the lifetime of a reference is part of its type).
> can encode logic in types in a way that’s impossible in most other languages
It’d be of great help if you could share an example of this along with an explanation why it’s impossible in a different language say one of Java/C++/Go
I would argue that F# would be the choice of language in place of Rust if you don't want to deal with Rust's type system. F# is immutable by default with good concurrency and a static type system.
That's a great suggestion I had forgotten about, which is strange since I'm a C# programmer. Part of me wants to really learn a Lisp to see what it is special about it that I keep hearing about. I tried Racket and Steel Bank Common Lisp but they didn't seem appropriate for the commercial programming I'm used to. Clojure is being used commercially.
I also really like Lisps/Schemes. I've always wanted to pick up Clojure but don't like how it thinly sits on top of the JVM compared to F# being deeply integrated. I always had trouble getting Clojure properly installed compared to just downloading .NET and having F# or easily downloading Racket.
You should absolutely try out F#. :) It's a great language.
Also, if you're looking for the magic of Lisp/Scheme, I think you might really enjoy Elixir/Erlang. Elixir has macros, has purely immutable data (there is _no_ way whatsoever to get mutable data unlike F#, Racket, Clojure, etc.), live code updates, and the BEAM VM, its process framework, and OTP are quite magical.
When I first learned Erlang, I felt I had come home. I mainly used Elixir though due to the available packages and jobs.
The late great Joe Armstrong is missed! Good suggestion, I will take a look at Elixer/Erlang. It's the least I can do for the laughs Joe gave me in his videos.
Shameless plug if you like videos: I gave a talk about Erlang, building the language (focus on semantics, not syntax) up from the fact that the = sign doubles as a runtime assertion.
Joe was indeed a great guy. I was lucky enough to spend some private time with him when he was visiting Chicago to give a talk, a true renaissance man with wide-ranging interests.
Good talk! I didn't believe that Go example was real at first. A bit strange. I always think of Alan Kay's message passing objects when listening to descriptions of Erlang and tonight I also thought about Kubernetes pods. The other thought is one you touched on is that some systems are monolithic so you have to handle errors. Thanks, I enjoyed that.
I would recommend taking a look at some of the schemes. In particular I've been having tons of fun with CHICKEN: https://call-cc.org/ - the fact that it compiles to C and can generate binaries is a great plus.
Clojure is a niche language that (for realistic purposes) is still tied to a single platform, the JVM, which (Clojure, not the JVM) looks more dead with every passing year. It never became popular and it's been steadily losing users. It's also not as general purpose as Common Lisp (ie. not suited for system or lowlevel programming).
If you're going to learn a niche Lisp, you might as well learn Common Lisp or Scheme which have well-specified standards, have stood the test of time and will still be around for decades to come.
Although niche, things are pretty lively in the community. Among other things this year great progress was made on Jank, the native LLVM-based implementation with seamless low-level C++ interop. As part of that work a test suite is being created [0] and now includes runners for all of the major implementations to compare compatibility, next best thing besides a formal specification.
Clojure will be around as long as the jvm. It’s mostly done at the core level, most updates are to leverage new host features nowadays. The rest is happily provided at the library level by the community (which is still very prolific).
And it’s not tied to the jvm per say, look at clojurescript (and derivatives) or the upcoming jank.
It’s far from dead. As much as I like CL, the ecosystem is a bit of a desert compared to the jvm.
Likely just not a statistically significant enough sample of any of those to justify them even putting them on the chart. Except maybe Dart, and that gets the "curse" of being front-end tech which for some inexplicable reason is underpaid.
Just to counter-balance the inferred conclusion that Common Lisp would not have any commercial usage (sorry, words are important, FUD is too close from hasty wording or hasty conclusions): https://github.com/azzamsa/awesome-lisp-companies/ (example companies using CL today, and yes some pick it for new projects, and yes some hire) (and I don't want to argue if the list is impressive or not: it's some commercial usage :D best,)
JVM is very much not dead even slightly. They just released virtual threads, which are ridiculously awesome. Also it's not tied to a single platform, clojurescript lets you write clojure in browsers and on node.js, and babashka lets you use clojure in a scripting environment via a single executable
I haven't tried clojurescript but I'm fearful of languages that run on top of other languages or platformks, because of complications that produces for debugging.
How do you debug ClojureScript? Can you modify the source-code while in the debugger? That is a huge time-saver, you debug and see a typo and fix it right away. My preference are influenced by my background in Smalltalk's "live" environemnt: you see the variables, the stack, and can change anything without having to stop the debugging session and then have to go back to the "editor" and then locate the place you (now know) you want to modify, and then start again.
I frankly miss the JVM. I work almost exclusively in Rust these days and haven't worked in Java or Scala since 15 years ago, and I do prefer working closer to the metal.... But... The JVM is an amazing mature runtime with a boatload of tooling. JMX, which has been there since almost the beginning, is the kind of thing missing from almost everything other managed runtime I've worked with.
The amount of R&D that has gone into making it execute with good performance, and its overall stability...
Yeah, it's got the curse of being boring.
I do think it is perhaps unfortunate that Clojure is tied so heavily to the JVM, because I actually don't think it gains much from that ecosystem... but it's a product of the time it was first written.
Actually hell. I'm between jobs, I like Lisp, and I miss the JVM. I've never worked in Clojure, but does anybody want to hire me to work in it? :-)
> I do think it is perhaps unfortunate that Clojure is tied so heavily to the JVM, because I actually don't think it gains much from that ecosystem... but it's a product of the time it was first written.
When I was doing more Clojure, I loved that it was on the JVM because it meant I got to use every Java library under the sun. There are tons of battle tested Java libraries that didn't have to be rewritten in Clojure, and getting to use them for approximately zero financial and runtime cost was a HUGE benefit of Clojure compared to other niche FP languages.
The JVM has suffered a fate worse than death: it's become so wildly successful that it's boring. So much enterprise shit runs on Java that it has sort of faded into the background noise of civilization and, like the System/360 (now Z/OS) before it, doesn't grab headlines anymore.
Which makes Clojure extra tempting because there is a bit of a infectious way to get Clojure i to corporations when you are always just handing the ops guys a "Java" we app bundled as a jar but secretly inside it's all Clojure compiled classfiles that work perfectly run on many JVM-based web servers with no additional effort.
I think Rich even alludes to this fact in one of his talks where it would be disallowed to run Ruby/Python/Rust whatever but it's Java then it's a know entity.
> the JVM, which looks more dead with every passing year.
Lol, only dying/dead in the febrile imagination of some HN commenters. The JVM has had some of the most explosive feature activity in the last several years. Java had several million greenfield projects in 2024-25 - among the top 6 greenfield programming languages according to the Github Octoverse.
Old Lisp posts are cool, then if you want a refresher of what's happening in the CL ecosystem (tools, libraries, compilers…) here's an overview of the last two years (shameless plug): https://lisp-journey.gitlab.io/blog/these-years-in-common-li... and very cool new projects appeared in 2025.
I'm curious why Lisp didn't gain mass popularity despite its advantages. In fact, I was wondering if it's popularity has event decreased in the past decade or so. I remember in the 2000s and even early 2010s, there were active discussion on Clojure, Scheme, and functional/logic programming in general. There seems much less discussion or usage nowadays. One theory is that popular languages have absorbed many features of functional programming, so the mainstream programmers do not feel the need to switch. My pet theory is that many of us mortals get the productivity boost from the ecosystem, in particular powerful libraries and frameworks. Given that, the amazing features of lisp, such as its s-expression, may not be powerful enough to sway users to switch.
> It seems to me that LISP will probably be superseded for many purposes by a language that does to LISP what LISP does to machine language. Namely it will be a higher level language than LISP that, like LISP and machine language, can refer to its own programs. (However, a higher level language than LISP might have such a large declarative component that its texts may not correspond to programs. If what replaces the interpreter is smart enough, then the text written by a user will be more like a declarative description of the facts about a goal and the means available for attaining it than a program per se).
Pretty accurate foresight in 1980, in the "Mysteries and other Matters" section McCarthy predicting declarative textual description replacing lisp as a higher-level programming language, basically describing todays LLMs and agentic coding.
That is remarkable foresight. I've had Google Gemini take a Dart program it wrote for me and had it convert it to TypeScript while adding some additional requirements - so declarative programming and treating code as data
> Pretty accurate foresight in 1980, in the "Mysteries and other Matters" section McCarthy predicting declarative textual description replacing lisp as a higher-level programming language, basically describing todays LLMs and agentic coding.
To me, that sounds more like Prolog than agentic coding.
How many people are using LLMs to replace coding in Lisp? What code are these former Lispers producing with LLM Agents?
I understand what you're trying to say, but I don't think LLMs were created as some replacement for Lisp. I don't think they've replaced any programming language, but they do help quite a bit with autogeneration of Python & Javascript in particular.
LLMs seem better suited to help with the Tower of Babel we've created for ourselves: aws commands, Terraform modules, Java libraries, Javascript/React, obscure shell commands, etc.
The strength of Lisps is in ability to define DSLs and then concisely express solutions for problems in that domain. Arguably no other programming language was able to exceed or even match that power until now.
The math behind transformers is deterministic, so LLMs could be treated as compilers (putting aside intentionally adding temperature and non-determinism due to current internal GPU scheduling). In the future I imagine we could be able to declare a dependency on a model, hash its weights in a lockfile and the prompt/spec itself will be the code, which corresponds to that insight.
> the prompt/spec itself will be the code, which corresponds to that insight.
What I've understood from discussions on HN is that LLMs are non-deterministic. Am I right? So the same prompt when executed again could produce a different answer, a different program every time.
That would mean the prompt is not a great 'highleve lanaguage", it would get compiled into a different Lisp-program depending on the time of the day?
I think when programmers are introduced to languages, most grok procedural ones easier than functional ones, hence Lisp and its derivatives have struggled in popularity for decades.
I have been thinking about the reason why Lisps aren't more popular today. I'm not sure yours is the right reason though. It seems like the statement you make would be no more true today than in the 80s, when Lisp was much more popular.
Ultimately I think it might just be fads. Object oriented programming came along at the same time as the web, when the demand for programmers grew dramatically. That may have crystallized OO and imperative languages as the "default" style. Would be interesting to see the alternate universe where JavaScript actually was a Lisp.
JavaScript has been called "Lisp in C's clothing". JavaScript is not a "pure" functional language but are any of the Lisps either? They might have immutability as the default. But I don't see why an Object-Oriented language could not have immutability as the default as well?
From what I've understood about Haskell is that it allows you to divide your program into parts which are either pure functional, or mutable. That is great when you read the program, you can know that what you are reading now is immutable, whereas in the some other well designated parts it is mutable.
But with Lisps isn't it the case that statement 1 can be immutable while the next statement 2 is mutable? In other words it mixes mutable and immutable calls into the same program-file without really isolating them from each other in any way. And that means if one part of the program is "impure", so is all of it. You can't isolate those parts except by following a convention, but conventions are not something that it enforces. And you can't know which parts of your program are pure except by reading the code-statements in detail. Am I right?
It occurred to me this morning that I should learn Clojure instead of Rust for non-lowlevel code because Clojure solves the same problems Rust solves in a much simpler way. I'm a fan of Clojure author Rich Hickey's "Simple Made Easy" talk but otherwise don't know either language in detail and need to do more research.
As an anecdote, about a year ago I realized I was not having that much fun learning rust. Randomly landed on clojure instead and have absolutely loved it.
Particularly as a noob, babashka is SUCH a good way to learn the language. I’ve written myself all sorts of fun utilities with babashka and have learned so much clojure along the way. Even got my coworkers to use my bb scripts!
The Clojure (or any Lisp) journey is very different, not because of the language per se, but because of the developer experience.
In Clojure, there's no appreciable compilation time. During my work week I barely, if ever, restart the application I'm working on: I'm working inside of it via a REPL connection.
It's an entirely different ball game and if you just compare language features you are missing out on an incredible interactive coding experience.
> Clojure solves the same problems Rust solves in a much simpler way
I'm curious about that, can you elaborate? I'm a beginner in Clojure and I only know a few concepts about Rust, but it seems to me that they solve (at least, currently) very different problems...
I only saw Rust being used in places where C or C++ would be used in the past (Linux kernel, CLI apps, desktop apps), while I only saw Clojure being used as a modern and functional Java and JS replacement.
Not to mention how different they are as languages (static vs dynamic typing, native vs jvm, borrow checker vs garbage collection)
The main problem that Rust tries to solve, and that functional programming (which Clojure heavily leans into) solves, is avoiding shared mutable state, which leads to data races and (potentially subtly) wrong concurrent programs. Functional programming avoids shared mutable state by avoiding mutable state. Operations are only represented as transformations instead of mutations. Other languages like Erlang / Elixir use message passing techniques like the Actor Model to avoid shared mutability. Instead of avoiding mutability, like in functional programming, in the Actor Model you avoid sharing, by instead sending messages around.
Rust is interesting because it solves the problem of shared mutable state, while allowing sharing, and allowing mutability, just not at the same time. State can be mutated until it is shared. While it is shared, it cannot be mutated. This is the goal of the ownership system in Rust.
One thing that jumped out at me is you don't need Rust's borrow checker to prevent thread race conditions because data in Clojure is immutable. That's a huge simplification over Rust. What I hear mostly about Rust is complaints about the borrow checker. I wrote a simple Rust utility and found it frustrating. But again, don't take my word for it because I don't know either language.
As someone who has gone deep into both functional programming (with Elixir, Clojure, and Scala) and also Rust, they solve the same problem in different ways with different tradeoffs.
The problem is that shared mutable state is incredibly hard to get correct, especially when concurrency enters the picture.
Elixir and Clojure sidestep the problem by making copying data so cheap that instead of sharing references to mutable data, you make all data immutable and copy it whenever you want to change it in some way. (Which is a classic technique: don’t like the problem? Solve a different problem that sidesteps the original problem in a creative way)
So you have a lot of functions of roughly the shape `f -> f` (return a new thing) instead of `f -> ()` (mutate a thing in place).
This possible at all by the clever use of some novel data immutable structures like HAMTs that are able to approximate the performance of traditional mutable data structures like hashmaps or arrays while presenting an immutable API.
As it turns out, this is a much easier programming model for most of us to get correct in practice (especially in the presence of concurrency) than sharing mutable state in an imperative programming language like C or Java or Python.
The tradeoff is that the immutable functional data structures actually do have a some performance overhead. In most domains it's not large enough to matter, but in some domains it is, and in those domains you really do need mutable state to eek out that last bit of performance.
Which is where Rust comes in.
In Rust's model, data can either mutable or shared, but not both at the same time. The Rust compiler computes the lifetimes of data throughout your program to ensure that this invariant is upheld, so mutable data is not shared, and shared data is not mutated.
The downside of this is that you have to internalize these rules and program to them. They can be tough to learn and tough to program with even after you have learned them, though it does get much easier with experience, I will say.
The upside of Rust's model is that you can have your cake and eat it too: you can keep the high performance ceiling of a true mutable data model while maintaining memory and resource safety.
In short, you can think of Clojure/Elixir as sidestepping the shared mutability problem at the cost of some runtime performance (though again in practice it is smaller than you would think), and Rust as tackling the shared mutability problem head on by transferring the cost of solving the problem to a more complicated compiler and a harder-to-learn programming model.
These are just my opinions having used both Rust and the immutable data functional programming stuff in anger. I'm not trying to present one as being better than the other, the key point is that they're both better than what came before.
Did you look into zig and their solution ?
It's worth noting that there's several implementations of persistent/immutable/functional data structures for Rust already, and a few basic "building blocks" (namely std::borrow::Cow, noted for its bovine superpowers) are even in the Rust standard library. It's possible that we'll see more of them standardized in the future if a case can be made that they're useful and a consensus is reached wrt. some kind of minimally viable APIs.
My read today is that the advantage of Rust over C/C++ is that the compiler enforces the rules, where in C/C++ you'd have to use a static source code analyzer to find omissions. Since Clojure uses Software Transactional Memory and Persistant Data Structures to only make copies of updated shared data structures, it seems like it could actually be faster than Rust/C/C++ depending on how efficient the copy is. I may have it wrong but it sure is interesting...
That’s my take after using Rust for half a decade. The type system is very powerful and can encode logic in types in a way that’s impossible in most other languages, which is how the borrow checker works (the lifetime of a reference is part of its type).
> can encode logic in types in a way that’s impossible in most other languages
It’d be of great help if you could share an example of this along with an explanation why it’s impossible in a different language say one of Java/C++/Go
I would argue that F# would be the choice of language in place of Rust if you don't want to deal with Rust's type system. F# is immutable by default with good concurrency and a static type system.
That's a great suggestion I had forgotten about, which is strange since I'm a C# programmer. Part of me wants to really learn a Lisp to see what it is special about it that I keep hearing about. I tried Racket and Steel Bank Common Lisp but they didn't seem appropriate for the commercial programming I'm used to. Clojure is being used commercially.
I also really like Lisps/Schemes. I've always wanted to pick up Clojure but don't like how it thinly sits on top of the JVM compared to F# being deeply integrated. I always had trouble getting Clojure properly installed compared to just downloading .NET and having F# or easily downloading Racket.
You should absolutely try out F#. :) It's a great language.
Also, if you're looking for the magic of Lisp/Scheme, I think you might really enjoy Elixir/Erlang. Elixir has macros, has purely immutable data (there is _no_ way whatsoever to get mutable data unlike F#, Racket, Clojure, etc.), live code updates, and the BEAM VM, its process framework, and OTP are quite magical.
When I first learned Erlang, I felt I had come home. I mainly used Elixir though due to the available packages and jobs.
The late great Joe Armstrong is missed! Good suggestion, I will take a look at Elixer/Erlang. It's the least I can do for the laughs Joe gave me in his videos.
Shameless plug if you like videos: I gave a talk about Erlang, building the language (focus on semantics, not syntax) up from the fact that the = sign doubles as a runtime assertion.
https://youtu.be/E18shi1qIHU
Joe was indeed a great guy. I was lucky enough to spend some private time with him when he was visiting Chicago to give a talk, a true renaissance man with wide-ranging interests.
Good talk! I didn't believe that Go example was real at first. A bit strange. I always think of Alan Kay's message passing objects when listening to descriptions of Erlang and tonight I also thought about Kubernetes pods. The other thought is one you touched on is that some systems are monolithic so you have to handle errors. Thanks, I enjoyed that.
This the “non-low level” code qualification.
I would recommend taking a look at some of the schemes. In particular I've been having tons of fun with CHICKEN: https://call-cc.org/ - the fact that it compiles to C and can generate binaries is a great plus.
How does Clojure do on McCarthy's desiderata from this paper, as you see it?
Clojure is a niche language that (for realistic purposes) is still tied to a single platform, the JVM, which (Clojure, not the JVM) looks more dead with every passing year. It never became popular and it's been steadily losing users. It's also not as general purpose as Common Lisp (ie. not suited for system or lowlevel programming).
If you're going to learn a niche Lisp, you might as well learn Common Lisp or Scheme which have well-specified standards, have stood the test of time and will still be around for decades to come.
Although niche, things are pretty lively in the community. Among other things this year great progress was made on Jank, the native LLVM-based implementation with seamless low-level C++ interop. As part of that work a test suite is being created [0] and now includes runners for all of the major implementations to compare compatibility, next best thing besides a formal specification.
[0] https://github.com/jank-lang/clojure-test-suite
Clojure will be around as long as the jvm. It’s mostly done at the core level, most updates are to leverage new host features nowadays. The rest is happily provided at the library level by the community (which is still very prolific).
And it’s not tied to the jvm per say, look at clojurescript (and derivatives) or the upcoming jank.
It’s far from dead. As much as I like CL, the ecosystem is a bit of a desert compared to the jvm.
But also: https://survey.stackoverflow.co/2024/work#3-salary-and-exper...
Prolog and Dart programmers earn the least, but Erlang and Clojure programmers earn the most? Something is fishy here...
>>Clojure programmers earn the most?
All the best finding a Clojure job though.
Im guessing they pay all that much, while simultaneously cursing themselves for not using Python instead, and swearing to never use Clojure again.
I know that as I have seen people do and say similar things about Perl and Erlang in the last decade.
I would take this statistics, like every other one, with a grain of salt, but still wanted to put it out there as a possible discussion point.
Likely just not a statistically significant enough sample of any of those to justify them even putting them on the chart. Except maybe Dart, and that gets the "curse" of being front-end tech which for some inexplicable reason is underpaid.
Yeah, that seems likely. Although it's lower than PHP!
Clojure is not going anywhere anytime soon.
It sees plenty use as Clojure/Clojurescript and Babashka. (and other niche variants). Jank is shaping up to be real nice too.
I prefer CL, but… clojure at least has some commercial usage and is by far the most successful of current lisps, if we do not count elisp.
Just to counter-balance the inferred conclusion that Common Lisp would not have any commercial usage (sorry, words are important, FUD is too close from hasty wording or hasty conclusions): https://github.com/azzamsa/awesome-lisp-companies/ (example companies using CL today, and yes some pick it for new projects, and yes some hire) (and I don't want to argue if the list is impressive or not: it's some commercial usage :D best,)
JVM is very much not dead even slightly. They just released virtual threads, which are ridiculously awesome. Also it's not tied to a single platform, clojurescript lets you write clojure in browsers and on node.js, and babashka lets you use clojure in a scripting environment via a single executable
I haven't tried clojurescript but I'm fearful of languages that run on top of other languages or platformks, because of complications that produces for debugging.
How do you debug ClojureScript? Can you modify the source-code while in the debugger? That is a huge time-saver, you debug and see a typo and fix it right away. My preference are influenced by my background in Smalltalk's "live" environemnt: you see the variables, the stack, and can change anything without having to stop the debugging session and then have to go back to the "editor" and then locate the place you (now know) you want to modify, and then start again.
I don't care if it's niche if it solves my problems and gets the job done faster.
I frankly miss the JVM. I work almost exclusively in Rust these days and haven't worked in Java or Scala since 15 years ago, and I do prefer working closer to the metal.... But... The JVM is an amazing mature runtime with a boatload of tooling. JMX, which has been there since almost the beginning, is the kind of thing missing from almost everything other managed runtime I've worked with.
The amount of R&D that has gone into making it execute with good performance, and its overall stability...
Yeah, it's got the curse of being boring.
I do think it is perhaps unfortunate that Clojure is tied so heavily to the JVM, because I actually don't think it gains much from that ecosystem... but it's a product of the time it was first written.
Actually hell. I'm between jobs, I like Lisp, and I miss the JVM. I've never worked in Clojure, but does anybody want to hire me to work in it? :-)
> I do think it is perhaps unfortunate that Clojure is tied so heavily to the JVM, because I actually don't think it gains much from that ecosystem... but it's a product of the time it was first written.
When I was doing more Clojure, I loved that it was on the JVM because it meant I got to use every Java library under the sun. There are tons of battle tested Java libraries that didn't have to be rewritten in Clojure, and getting to use them for approximately zero financial and runtime cost was a HUGE benefit of Clojure compared to other niche FP languages.
The JVM has suffered a fate worse than death: it's become so wildly successful that it's boring. So much enterprise shit runs on Java that it has sort of faded into the background noise of civilization and, like the System/360 (now Z/OS) before it, doesn't grab headlines anymore.
Which makes Clojure extra tempting because there is a bit of a infectious way to get Clojure i to corporations when you are always just handing the ops guys a "Java" we app bundled as a jar but secretly inside it's all Clojure compiled classfiles that work perfectly run on many JVM-based web servers with no additional effort.
I think Rich even alludes to this fact in one of his talks where it would be disallowed to run Ruby/Python/Rust whatever but it's Java then it's a know entity.
You're saying that Clojure is looking more dead, so you suggest... Common Lisp? That looks considerably more dead than Clojure.
I'm not sure that Common Lisp looks less dead, but rather, more eternal.
> the JVM, which looks more dead with every passing year.
Lol, only dying/dead in the febrile imagination of some HN commenters. The JVM has had some of the most explosive feature activity in the last several years. Java had several million greenfield projects in 2024-25 - among the top 6 greenfield programming languages according to the Github Octoverse.
Old Lisp posts are cool, then if you want a refresher of what's happening in the CL ecosystem (tools, libraries, compilers…) here's an overview of the last two years (shameless plug): https://lisp-journey.gitlab.io/blog/these-years-in-common-li... and very cool new projects appeared in 2025.
I'm curious why Lisp didn't gain mass popularity despite its advantages. In fact, I was wondering if it's popularity has event decreased in the past decade or so. I remember in the 2000s and even early 2010s, there were active discussion on Clojure, Scheme, and functional/logic programming in general. There seems much less discussion or usage nowadays. One theory is that popular languages have absorbed many features of functional programming, so the mainstream programmers do not feel the need to switch. My pet theory is that many of us mortals get the productivity boost from the ecosystem, in particular powerful libraries and frameworks. Given that, the amazing features of lisp, such as its s-expression, may not be powerful enough to sway users to switch.
> It seems to me that LISP will probably be superseded for many purposes by a language that does to LISP what LISP does to machine language. Namely it will be a higher level language than LISP that, like LISP and machine language, can refer to its own programs. (However, a higher level language than LISP might have such a large declarative component that its texts may not correspond to programs. If what replaces the interpreter is smart enough, then the text written by a user will be more like a declarative description of the facts about a goal and the means available for attaining it than a program per se).
Pretty accurate foresight in 1980, in the "Mysteries and other Matters" section McCarthy predicting declarative textual description replacing lisp as a higher-level programming language, basically describing todays LLMs and agentic coding.
That is remarkable foresight. I've had Google Gemini take a Dart program it wrote for me and had it convert it to TypeScript while adding some additional requirements - so declarative programming and treating code as data
> Pretty accurate foresight in 1980, in the "Mysteries and other Matters" section McCarthy predicting declarative textual description replacing lisp as a higher-level programming language, basically describing todays LLMs and agentic coding.
To me, that sounds more like Prolog than agentic coding.
I don't see the connection to LLMs. With LLMs, you have a highly non-deterministic system that is also highly probable to be incorrect.
It seems like a stretch to say that's what McCarthy was thinking about regarding declarative facts and goals driving a program.
How many people are using LLMs to replace coding in Lisp? What code are these former Lispers producing with LLM Agents?
I understand what you're trying to say, but I don't think LLMs were created as some replacement for Lisp. I don't think they've replaced any programming language, but they do help quite a bit with autogeneration of Python & Javascript in particular.
LLMs seem better suited to help with the Tower of Babel we've created for ourselves: aws commands, Terraform modules, Java libraries, Javascript/React, obscure shell commands, etc.
I've been having a great time generating Common Lisp code with LLMs. eg. https://github.com/atgreen/cl-tuition , https://github.com/atgreen/ctfg , etc.
Pull request incoming to add back your missing README emojis.
The strength of Lisps is in ability to define DSLs and then concisely express solutions for problems in that domain. Arguably no other programming language was able to exceed or even match that power until now.
The math behind transformers is deterministic, so LLMs could be treated as compilers (putting aside intentionally adding temperature and non-determinism due to current internal GPU scheduling). In the future I imagine we could be able to declare a dependency on a model, hash its weights in a lockfile and the prompt/spec itself will be the code, which corresponds to that insight.
> the prompt/spec itself will be the code, which corresponds to that insight.
What I've understood from discussions on HN is that LLMs are non-deterministic. Am I right? So the same prompt when executed again could produce a different answer, a different program every time.
That would mean the prompt is not a great 'highleve lanaguage", it would get compiled into a different Lisp-program depending on the time of the day?
[dead]
[dead]
I think when programmers are introduced to languages, most grok procedural ones easier than functional ones, hence Lisp and its derivatives have struggled in popularity for decades.
I have been thinking about the reason why Lisps aren't more popular today. I'm not sure yours is the right reason though. It seems like the statement you make would be no more true today than in the 80s, when Lisp was much more popular.
Ultimately I think it might just be fads. Object oriented programming came along at the same time as the web, when the demand for programmers grew dramatically. That may have crystallized OO and imperative languages as the "default" style. Would be interesting to see the alternate universe where JavaScript actually was a Lisp.
JavaScript has been called "Lisp in C's clothing". JavaScript is not a "pure" functional language but are any of the Lisps either? They might have immutability as the default. But I don't see why an Object-Oriented language could not have immutability as the default as well?
In the 80's Lisp was already over 20 years old.
Common Lisp supports both styles. Shoot, it probably favors procedural over functional a bit.
From what I've understood about Haskell is that it allows you to divide your program into parts which are either pure functional, or mutable. That is great when you read the program, you can know that what you are reading now is immutable, whereas in the some other well designated parts it is mutable.
But with Lisps isn't it the case that statement 1 can be immutable while the next statement 2 is mutable? In other words it mixes mutable and immutable calls into the same program-file without really isolating them from each other in any way. And that means if one part of the program is "impure", so is all of it. You can't isolate those parts except by following a convention, but conventions are not something that it enforces. And you can't know which parts of your program are pure except by reading the code-statements in detail. Am I right?
If you're into Haskell, you may like Coalton. It's an FP language written in CL with seamless interop.
https://github.com/coalton-lang/coalton
Common Lisp is like the vast majority of programming languages, yes.
It supports basically all styles which makes it wonderfully useful in whatever domain you happen to find yourself in.
nice, I was hacking common lisp this weekend.
Also this video was interesting, Oral History of John McCarthy: https://www.youtube.com/watch?v=KuU82i3hi8c&t=1564s
[flagged]