I love clojure, but it's really lost a lot of the momentum it had as many imperative languages have adopted parts of functional programming (and much for the better) over the last many years.
On the other side I've felt a lot of the ecosystem work that was done has a more "timeless" quality. Coupled with java interop I haven't ever felt wanting when I do reach for it for some hobby projects I keep up with.
One thing I will say, since it takes a different tack and philosophy, I think any programmer learning some of it benefits from the different perspective.
In my experience, the subsets of the community around clojure were one of the biggest problem with it. It's gotten better over the years, but circa 2016 - 2018 it had a spike in popularity despite being very hostile to newcomers.
There was an almost apologist attitude towards rough edges or failure modes folks new to the community would fall into. I managed to work with it for a time despite that, but it left me with a bad taste in my mouth. It's really important to make your ecosystem and communities welcome to new users or they're destined to fade.
> ...had a spike in popularity despite being very hostile to newcomers.
To be fair the community itself, as humans, was very welcoming to newcomers. Really super nice and helpful folks.
If anything was "hostile" it was the dominance of emacs and very limited options for other tooling. That, and the horrifically unhelpful leaky abstractions in the stack trace when something went wrong. It's a big step, if you don't already know emacs to learn emacs (at a fairly advanced level) AND a new very different programming language.
I see now there's a vscode option with Calva. I haven't tried it. Might do that someday. Really wanted to like this language!
I'll second that the popular tooling, while powerful and reliable, its just not user friendly.
The official Clojure CLI, for example, is just plain confusing, and that's most people's first impression to the entire ecosystem. The config files, while they use the wonderful `.edn` format, are also not intuitive. Newcomers are the most likely people to encounter the most amount of error messages... which are famously difficult to read.
And that's before you even get into REPL configuration, which involves coordination with your editor process, a client process, and a server process. Even if you have a tool like Calva or CIDER managing it for you, you'll still get confused when something goes wrong unless you grok all the moving parts.
Even if you figure that all out, you still don't have Parinfer or equivalents setup yet in your editor. Also, clojure-lsp tends to require some configuration to get working the way you want. And that's before you get started with ClojureScript, which brings the complexity to another level entirely.
Despite all this, I love Clojure. It's an expert's language, even though it shouldn't have to be. Once you learn this stuff, you respect why much of this complexity exists. It's inherent to the amount of power the language gives you.
But doesn't mean we can't make it easier to use and get started with.
> The official Clojure CLI, for example, is just plain confusing, and that's most people's first impression to the entire ecosystem. The config files, while they use the wonderful `.edn` format, are also not intuitive.
I completely agree; it is unfortunate they don't spend more time officially recommending leiningen.org. A beginner attempting to use the built-in CLI is going to lead to a poor first 3 months.
This matches my experience as an amateur programmer. The initial hill was steep, but I don't think it was because people weren't friendly.
There is one cultural thing that might be confused with unfriendliness. Sometimes people react badly if someone posts incorrect information. But I think that's good. When you search for information about Python or PHP you have to wade through quite a bit of junk. Ironically, it's sometimes easier to find correct answers for Clojure.
Clojure itself is very clean and consistent, it's got a lot of polish to it, which makes it comparatively easy to learn. And there isn't that much of it. But for a long time the tooling was hard.
That's far less of a problem than it used to be. deps.edn and shadow-cljs both made things easier, as has Cursive. People say nice things about Calva, but I don't know it.
I'm a big fan. Babashka alone is enough to make learning Clojure worthwhile. Also, for someone like me, it's kind of nice that it feels almost finished. Once you learn it, you know it, and now that the tooling has settled down a bit you don't have to keep running to keep up.
People posting the wrong information is a great opportunity for a community to explain why it’s wrong. We lost that take on community and it’s a major loss for our entire industry. It’s remarkably hard for people to figure out why they’re wrong when they’re wrong.
I don’t think the solution is the Usenet-esque “you are wrong and your breeding is suspect” way. But there’s a very good place in the middle and I’d really like to find that place.
Business wise, I think we’re using the wrong paradigm in some major places. Maybe we can beat that while I’m still alive and that would be a net win for our whole craft.
the tooling is the reason i gave up when i was interested in learning clojure. everywhere pretty much said that emacs was the "correct" editor to use for clojure, i tried it out for a bit but ultimately learning a new language and a new editor at the same time was just too big of an ask.
i tried calva with vscode afterwards but it was basically the same thing, calva has paredit which overrides the keyboard navigation and there was no way to disable it. somebody had asked for the option to disable it on the github but the creator said something along the lines of calva without paredit wasn't the way he wanted it to be used, so i just picked another language to learn.
Wow. I'm the creator of Calva and I can tell you that I do not have an opinion on how to use it. I would never say something like that, and now I wonder what I could have said that was interpreted this way...
By default Calva Paredit overrides three or so keyboard shortcuts. This is to help the users to not accidentally delete brackets, which in turn keeps the support questions down about broken Clojure code. I have tried to make it super easy to disable these overrides. There's a command for it. There's a button in the toolbar for it, and there's a setting for it.
There's also a setting for removing all Paredit bindings, even those that are not overriding any default ones. (This setting is for people who use Paredit, but want to provide their own shortcuts entirely.)
it's nice, but I used to write Java, and even getting IntelliJ setup on my laptop took a lot of fiddling with JVM versions and getting it to recognize my Clojure install.
To this day, I will still have weird issues where Cursive won't run a project, and Emacs will.
I use https://sdkman.io/ to manage JVM versions, have you tried that? I haven't used Cursive, maybe it does something weird, but in general IntelliJ seems to accept it just fine in my everyday work.
A somewhat similar thing I ran into is that existing Clojure code can be incredibly difficult to grok if you don't already know the language very well.
Some of this comes from lisp's minimalist syntax, which makes it hard to even know what kind of thing you're looking at when you're encountering a new thing for the first time. But the problem is also compounded by some of Clojure's more distinctive (and powerful) features such as ad-hoc polymorphism and using maps to pass function arguments.
The closest analogy from imperative languages that I can think of is another language that's famous for being incredibly productive in the hands of a skilled user, but whose code tends to feel kind of write-only: Perl.
Here, the only problem is that you don't know what the symbols and some of the notations mean. You can look at the unfamiliar syntax and know what is a child of what. Most operators are words you can search for.
I may be wrong, but I think the parent poster was talking more about the language and ecosystem than the community. I, too, have found the community to be amazing. But the language itself used to be quite frustrating to learn. It's better now, but I think that by the time it got fixed many companies and teams had already been burned.
Clojure is particularly vulnerable to that because it really is an enterprise applications language. That makes it more vulnerable to learning curve problems than a language like Rust whose most direct competitors are other languages with comparably steep learning curves.
Yes, I agree with you, learning is complicated, because it's mostly un-learning habits you had for 20+ years. Stack traces suck, but after a while you grok them. The clojure/core is full of niceties, but it's so big you need a map just to know what's in there. And still...
> many imperative languages have adopted parts of functional programming
nailed it. I don't know much about functional languages other than a haskell course back in the day, but I don't want to do functional all the time. It plays great in some situations and I am happy to use those language subsets in my daily coding, but I don't need my entire application to be written in an esoteric language
This is of course a popular opinion and pretty much the C++ philosophy. Unfortunately a lot of the benefits of functional programming cannot be fully realised unless you are "all in". The paper "The Curse of the Excluded Middle" is somewhat blunt but it makes some good points: https://queue.acm.org/detail.cfm?id=2611829
In my experience jumping from a Clojure shop to a large Java shop a few years ago, the benefits of persistent data structures are overstated. Mutable collections are just as good for 99% of use cases. And they're a lot faster (in single threaded code) and occasionally mutation makes things easier.
The selling point of Clojure is that persistent data structures prevent several classes of bugs (unintended mutation, locking, etc.). But in reality -- as long as your team members are good enough programmers -- I don't see these kind of bugs happen in practice.
That being said I love Clojure and the standard library is the best out of any language. It is a great choice in the small market of "projects that need simple and correct code".
Looking at an object in my debugger back in my call stack and assume I'm looking at the value as it was but in reality it was mutated in a subsequent stack gives me trust issues
It's probably fine most of the time it's just when I have to get into the weeds I want to have stability
This is like saying "the benefits of functional programming are overstated". If you are happy with mutable collections, you've happy with mutable variables, pervasive side effects and essentially the status quo. Many of us are not happy with the level of software quality out there and the status quo, Rich Hickey included.
> the benefits of persistent data structures are overstated.
Well, what else is overstated?
- Structural editing? Fine.
- REPL-driven development? Okay, let's throw that out the window.
- Hosted nature and the interop? Gone.
- Destructuring? Eh, we kinda have it in Javascript, right?
- Concurrency support? Who needs that shit, anyway, right?
- Simplicity and elegance? Arguable. Some like verbose Typescript code more.
- Functional programming? What the heck is it even?
The point I'm trying to make is that you can't just "remove" an essential part of what makes a language. Rich Hickey took a year-long sabbatical (or was it two or even three years? I forgot) and used his savings to get this aspect of the language right. Without the immutable collections, the language would've been an entirely different beast.
I think the persistent collections are generally worth the cost. IIRC, for HAMT maps/sets for instance, they're about twice as slow for reads and four times as slow for writes. For bulk updates, you can also slip into using transients, and then when you're done, "freeze" it back into a persistent data structure.
I only wish that the transient collections would support more different kinds of writes, like support all operations on java.util.List/Set/Map kind of thing. Forget which ones aren't present but I remember there being a couple...
There's nothing baloney about SSA form. I'm sorry to say it, but C is just not close to the metal any more. Even if you are able to hand optimise something so it works well on one architecture, it likely won't be optimal for another.
As for Haskell, it does pretty well being 100 times faster than Python with 100 times less the number of people working on it.
I believe that your interpretation of what’s actually happening is what’s baloney.
The fact is that you Haskell people only talk about the optimizations that can sometimes open on immutable data in specific circumstances. What you generally ignore is the optimizations that immutable data permanently locks you out of with no recourse.
As with most things programming, immutability should be considered a tool, not a rule.
You seem to think that functional programming and in-place updates are mutually exclusive. This is not the case, e.g. Haskell supports mutation as a tracked and controlled side-effect. It can even give static guarantees that a function is pure even it uses mutation internally.
Recent research even suggests that compilers can add the in-place updates for us: https://www.microsoft.com/en-us/research/publication/fp2-ful...
I don’t really care which functional programming advocate you’re quoting. They’re all liars when they make these claims.
You can say SSA, static guarantees, internal mutability, blah blah blah all you want. When third party, not specifically chosen anecdotes to make FP look good, measurements stack up to the claims, we can have a better conversation.
It’s not looking good though, cause these claims of “actually, Haskell is faster than C because compiler magic” have been going on since well before stable Haskell like 15 years ago, and they’ve been lies for just as long.
Functional programming is basically maths, it solves the problem of how to compose software safely. I struggle to understand why anyone who really cares about their craft would not want this. In fact, many want it so badly they are willing to make sacrifices for it (performance, esoteric languages).
Should have maintained a python interoperable runtime. Less and less people use JVM languages for things like web apps, data eng, data science, ML, etc.
On the other side I've felt a lot of the ecosystem work that was done has a more "timeless" quality. Coupled with java interop I haven't ever felt wanting when I do reach for it for some hobby projects I keep up with.
One thing I will say, since it takes a different tack and philosophy, I think any programmer learning some of it benefits from the different perspective.