I've created some great apps, and great libraries (in both Clojure and Java).
I often describe Clojure as "the least worst programming language", which is an off-handed complement, but I think accurate. Things you don't like can generally be fixed (at least locally) using macros and libraries. The core is strong, a good basis for building things ... and as described all over this thread, stable.
As you master your tools, you gain a level of speed and precision in your work that I have not found elsewhere. The REPL-oriented workflow is a central value proposition in Clojure, and many features (and a few limitations) of the language exist to properly support it.
Working in Clojure feels like I'm working "with" my code, molding it like clay. My prior experiences in Java and Objective-C were so much slower, with long code-compile-test-debug cycles that are compressed down to instantaneous responses in the running REPL.
I've been working on a large modern Java application lately and have never really felt the need for a REPL workflow even after having been exposed to it in Clojure. I tend to structure my Java code so it can be easily unit-testable and then just run the suite of unit tests (several thousand) in a few seconds as needed.
i find core.spec did wonders for that problem.
also, i have a tendency to write a lot of in-code documentation, whichever language i use. so it probably helps too.
I wish Hickey had built gradual typing in to the language.
I still love Clojure anyway.
What macro do I use to make it not run on the JVM? :)
But it runs on other things—Microsoft's CLR, Dart's runtime, JavaScript's runtime, Erlang's runtime, and with Jank, on top of LLVM.
You can still get mutability and I do this on every project. But it's a very small percentage of the code, less that 1%, and also well-defined.
Something like FlowStorm [0] isn't really practical in anything but Clojure, and things like Clerk [1] are easy and very natural.
Immutable data pairs great with REPL.
Because data are immutable, you don't need to care about where that data come from and where it will go. Just focus on what you need to do with that data at the point you work.
Everything is localized due to immutability.
The REPL let me test my changes while inside the thing as it ran. No problems. Someone wrote a nice *recording* debugger too which helped immensely -- no more "oops, I'm past the interesting part and have to start over"
* in prod we usually give it a small number of large instances
I'm used to using TDD for fast feedback as I'm molding my code. Do you miss unit testing? Or, do you find that the REPL in no way obviates unit testing?
And, do you miss static typing?
BTW, when Clojurians talk about REPL, it's not about that separate window where you type and run the code as in other language such as python. They are talking about an invisible REPL running behind the scene, to which they send code within their editors, and the results show up in the editors too.
There's no need to "miss static typing" in Clojure. If I need static typing, I just write deprotocol and deftype in Clojure, as many Clojure libraries do.
One can develop with TDD in Clojure quite smoothly depending on choice of tooling; with CIDER in Emacs there are keyboard shortcuts to run tests for the current namespace or the entire project, so feedback can be very fast (if your tests are fast). I've also used (some time ago) test runners that stay running and re-test when a file is saved.
In fact, it can be nice to do one's explorations in the REPL and then reify one's discoveries as tests.
Regarding types: I will say that working on larger Clojure (and Python) projects with somewhat junior teams made me more curious about type systems. Clojure's immutable collections and the core abstractions they are built around are great, but it can take some skill and discipline to keep track of exactly what kind of data is flowing through any particular part of your program. But, there is some support for à la carte strictness in the language via Spec, Malli, structured types, etc.
With clojure-lsp, deps.edn, and more REPL tooling (conjure in neovim in my case), the situation is better now. I find myself reaching for Clojure for almost everything these days - from scripting to data crunching to quick web apps to database work. Clojure is an amazing tool once you grok it - closest thing to a super-power we can get.
> working "with" my code, molding it like clay
This the best description. Clojure feels very fun/interactive but simultaneously feels rock solid for production work. There is no gap between "notebook" and "prod". Zero compromises. Most other languages pick one or the other (Python - interactive but plagued by runtime errors, Rust - rock solid but clunky to iterate and experiment)
If REPL is the main value proposition, how is it better from average JavaScript development? Dev tools allow you to basically interactively work with your code.
Another detail is that the whole culture of the language, oriented towards immutable data, makes it very easy to evaluate almost any sub-expression in your code, which makes the whole code introspectable in a very playful and dynamic way.
I don't think this is possible with JavaScript.
And you know what? Finally, I realized - I don't have to explain to anyone in exact detail why I have not found the same deep love in C, C#, Python, Javascript, Typescript, Ruby, Go, Java, Kotlin, Swift, Lua, Haskell, and many others. Why do I need anyone's permission to love a tool? I love it, and I love it for many reasons - theoretical, practical, emotional, fiscal.
Sure, I can get behind your excitement for Rust, Kotlin, OCaml, Elixir, Julia - you name it, but please, please do not try to "educate" me about my choices. I don't care about YOUR personal predicaments with Clojure/Clojurescript/Babashka/nbb, even Fennel. You find Clojure not to be worthy of your time - it's YOUR loss. My love for Clojure is not due to MY skill issues, not the result of MY inexperience, not because "I'm in a bubble," or "I don't know any better," or have zero knowledge of type systems, category theory, OOP or design patterns.
Sure, Clojure is not without deficiencies - no tool is ever perfect. Yet pragmatically, no other programming language in the category of general-use PLs today satisfies me more than Clojure, no other language is nearly as joyful to use. I'm sure at some point my stance will change, I will find some other "perfect" language for me, and 100% guaranteed - it will too have some deficiencies and people will be arguing for the merits of choosing it for the job. Until that day, let me just say it again - "I fucking love Clojure!"
Common Lisp was the most mind-blowing language I ever touched, and it seems the creator of Clojure really filled the gap between the brilliant simplicity of Lisp as a language and the access to a mature ecosystem. Maybe I should try Clojure as my next language (I am enjoying Rust for now; Rust macros are also cool, but way more complicated)...
1) runs on the JVM, access to any Java or Python library within Clojure without wrappers
2) an immutable-by-default language with a standard library that takes advantage of it
3) the best out-of-the-box concurrency story of any language I know of
4) a very well-developed ecosystem for developer tooling and general project stuff
Common Lisp is very fun, but the stress level is definitely higher with it due to the mutability and the generally less well-designed APIs. Only lists are actually functional, concurrency is YOLO-tier, etc.
I have ADD and I once heard that devs with ADD/ADHD have an incredibly small heap size for context but compensate for their weakness by being great at solving logical problems in that small heap. Types have been essential for me when functioning in code bases. I really struggle with pure JS and untyped Python.
Clojure was similarly hard for me. What tools and/or techniques do such folks use for comprehending already written Clojure code?
Even if I have a smaller total heap size (maybe), personally my hyper focus allows me to nearly dedicate all the heap space to the specific task at hand. I probably outperform neurotypical people here. I just can't have anything else in my head. Task switching kills me.
So it is hard to say cause everyone is a bit different.
For me the interactive, REPL-based workflow makes my ADHD brain very happy. Always having a program running is really nice.
Plus immutability makes it much easier to reason about things.
I do like static typing as well and I could see how it might help. I strongly believe that gradual typing allows for the best of two worlds, so that you can do both exploratory, interactive programming and type driven programming, depending on your needs.
Not sure how well the solutions for gradual typing in Clojure work though. I have only experience with Common Lisp. Coalton might the exactly what you need: https://github.com/coalton-lang/coalton
In addition to that, a real REPL programming really helps to do small tests and understand the code quickly, immutable data structures with data-oriented approach and locally scoped code blocks combined with structural editor are godsend as well.
You mean dynamic typing, I understand.
Clojure (and Common Lisp) is strongly typed, so if you expect type A and you give a value of type B, an error will be raised.
On Common Lisp, which is an interactive development language, you just inspect the stack frame where the error was raised, find the problem, correct the code, recompile your function (while the code is running), and "restart" the stack frame, so the execution continues (without having to restart or redeploy everything and try to replicate the bug). Thus, it is no big deal at all.
On Clojure i'm not so sure how extensive is the interactive support. But there is "spec", which can help.
When you're writing software you benefit from libraries the community made, and lots of people end up writing libraries and contributing back. It's possible Zig is much better for C, but they're failing to gain users due to lots of C developers continuing to use C for new projects, whereas if there were more users maybe the Zig ecosystem would be larger, making it easier to write larger pieces of software.
And I think basically all software is a collaborative effort. Users have investment in tools they think are useful, and frequently contribute or even take over maintenance on critical software. In that case they need to deal with whatever technical decisions that project made. Even commercial software can be abandoned as a buggy mess due to technical choices forcing users to migrate, or eventually open sourced (blender, doom, etc) in which case private technical choices become public. Also I think a lot of people have been forced to contribute (i.e. professionally) to projects that initially made very poor technical decisions and have been scarred by it.
No tool is perfect, and abstract technical debate is awful, but I think it's hard to say there isn't worse and better software, and I think it's worth the effort to put in effort to debate to try to discern and move from worse to better tools since the whole community benefits that way.
Edit: re-essayed
With the right discipline (specs, obsessively normalising all data at the boundaries, good naming conventions) this wouldn't have been a problem, but that discipline is optional, and headbanging aggravation results.
(This is, of course, a generic "dynamic typing" problem, but that's a key feature of Clojure)
I've seen plenty of tomatoes here on the orange site, thrown at Clojure.
Interestingly, years ago, when I was deciding if I should learn Clojure, I have typed into Google "why Clojure sucks". That's actually my usual "research technique" for any new tool - after the initial intro and the wikipedia pages, I typically do that and try to find some criticism, in order to remain level-headed. And guess what? To my surprise, instead, I found a plenty of compelling reasons to learn the damn thing, which I did. That has changed my life, not exaggeratingly, quite for real.
So my conclusion and advice to young programmers? Use whatever tools make you happy. Don't worry about their popularity, don't listen to couch-surfing "experts", try them for yourself. Be skeptical, first and foremost about your own reservations, thoughts, and feelings - something you dislike initially may change your perspective later. Conversely, be looking out for even better ways - remember, it's always possible to find renewed joy for the craft, even after decades of trying different things. There's always something out there that would feel like it was made for you to enjoy it.
The stacktrace-barf has improved a bit in recent versions as I recall, although I've lost the ability to see them by now.
The few folks I know using it are very happy with it, and are very experienced, and talented talented polyglots themselves.
For that reason I'd not rule it out, even if I'm not looking to make a jump or change, but I might try it out.
The article is excellent and I agree with everything in it.
The stability of the language is unbelievably useful. I look around and it seems it isn't valued in many other ecosystems where people have to rewrite their software regularly. I can't afford to rewrite my app.
There will be plenty of armchair critics here, with cliché knee-jerk reactions (parentheses, JVM, startup time, etc). If you intend to form an opinion, I would suggest you read only into the insightful posts, from people who actually used the language, or from critics who present well thought-out criticism, not just a shallow knee-jerk reaction.
There are good reasons why I said it was only possible with Clojure and ClojureScript. Conciseness, expressiveness, long-term stability, the ability to share business logic code between the client and server, same language used for data serialization (e.g. no JSON), good async code support (core.async), transducers for code reuse and performance, and more.
We bootstrapped for 5 years to well over $1M+ ARR before recently closing a seed round[1], Clojure played a large part in our ability to deliver as a small team. Also in our general happiness as programmers, it is a nice language to work in.
We will grow our Clojure core product team over the next couple of years, but mostly the funding round is about balancing our business to keep up with our product delivery.
Clojure has been very good to me (I had 15 years on the JVM prior to moving to clj/cljs in 2013-ish). YMMV.
[1] https://factorhouse.io/blog/articles/from-bootstrap-to-black...
The problem started when the honeymoon phase ended, and the codebase grew as the business gained traction. Dynamic typing became a burden, and once the key people moved on, they struggled to hire developers who wanted to write Clojure.
Also, JVM juju shooed many away. After I left, a coworker told me they had started rewriting part of it in Go, and that was going alright. Now, their stack mostly consists of Python for LLM stuff and Go for the main backend. There’s still some Clojure running legacy systems that haven’t yet been migrated over.
Golang can make even Python look terse.
There's practically 0 abstractions to meaningfully tame large code bases. You just end up writing same/similar code patterns over and over again.
If you are willing to go down that path I'd recommend using Java entirely. You get the full enterprise thing.
At your clojure job, we’re y’all using spec? I haven’t looked into it yet, and I’m wondering how much it mitigates the annoyances of dynamic types
Spec is about asserting structure at domain boundaries; once you're inside a context, it will not do anything.
i.e. If you're connecting stuff together and you want to make sure the state is correct as you pass between contexts -> great!
If you're writing stuff and internally you miss having a strong type system... uh... I don't think it's really going to help you.
One thing I grew to really love is how small my changes were when I’m just adjusting a decidedly brownfield chain of functions that operate on data. With go in place at work, I added a couple fields to a core data type in my business and I ended up with thousands of lines of changes to pipe them everywhere. Doing the corresponding change in clojure would be <100 lines. I do miss the feeling I get with Haskell that if it type checks, I’m (maybe) good, but like Rich says “List[A] -> List[A] tells me almost nothing about the reverse function.”
Also, is running your "hello world" still going to be incredibly slow, or has something changed in the core system (I know I'm supposed to fix that with graails. Or is it babashka ? Or something else, I suppose.)
It's really sad, because i just love the language. Reading about clojure is a pleasure. Trying to write anything has always been a blocker to me, though. Maybe that's the true "immutable" nature of the language ?
If you care about startup time (I don't, my app starts only once), you can use babashka for scripting.
Alternatively, open the project in IntelliJ with Cursive installed or VSCode with Clava or other supported editors and start evaluating code at the repl.
Go through a few tutorials, then go through one of the free books available online. Don't give up when you're stuck.
The language has a steep learning curve because it requires thinking about the program in a different way than many mainstream languages. But it compensates by giving you many 'aha!' moments which make the day :).
All that stuff still works and I don’t think any of them broke their APIs? A lot of people still use lein for example.
You’re talking about new choices coming along, which is a good thing.
Of all the ones you listed, only one is a product of the core team, so it’s not like there has even been “change” on any official level.
If your mindset is, “I need to be on the latest hot thing” that’s about you, not Clojure. You’re allowed to keep building your projects using any of those tools, they still have the same capabilities.
Beware here: it might sound natural to you, but many (and I many _many_) people are working on stacks where "there has been no update to this lib for 6 months" means "the project is discontinuated and has been replaced by something else, it's a waste of time."
So, it might be worth adapting the messaging. For example, there is an awesome-clojure page with a kitchen sink of every possible libs, some of which are dead, and some of which might not be.
Is there a "boring-clojure" page, where, sure, not everything is awesome, but you can be confident that using this lib and that tool and that IDE is going to, basically, "just work" for the foreseenable future ?
[0] Not sure what the correct term is here, but I mean the official default one; I know there are other implementations, and my vague recollection is that there's at least one other one that's either sponsored or maybe even fully developed by Oracle, and that the OpenJDK version is the "canonical" non-enterprise one now anyhow, so saying " first party" feels like it might add more ambiguity than it would resolve
But you're also not recompiling on code change. You're just reloading a function in the REPL. So you only have to load once and then your dev cycle is painless. But the startup time is bad for things like serverless functions unless you use something like GraalVM.
bb is Babashka: a pre-compiled (using Graal), interpreted, scripting language version of Clojure.
In terms of realistic work:
~/workspaces/github/pedestal/tests > time clj -X:test {:in user/eval2321, :line 13, :thread "main", :dev-mode? false}
Running tests in #{"test"}
...
Testing io.pedestal.test-test
Ran 391 tests containing 1180 assertions. 0 failures, 0 errors. clj -X:test 30.15s user 2.04s system 203% cpu 15.838 total ~/workspaces/github/pedestal/tests > java -version openjdk version "23.0.2" 2025-01-21 OpenJDK Runtime Environment Corretto-23.0.2.7.1 (build 23.0.2+7-FR) OpenJDK 64-Bit Server VM Corretto-23.0.2.7.1 (build 23.0.2+7-FR, mixed mode, sharing)
That's on my Intel MacBook Pro. Pedestal's test suite loads a good amount of Java classes and Clojure namespaces.
To make things faster, there's ahead-of-time compilation (which basically captures the read-eval-create-bytecode part of loading a Clojure namespace as Java .class files that can be packaged into your app).
The experience has gotten worse and worse now for a decade. The core team have continued to take things in a worse direction (supported by a small group of fanboys) and most newcomers are now completely baffled by the tooling.
Leiningen attempts to be everything to everyone in terms of building, testing, and packaging Clojure code. It's Clojure's version of Maven.
cli/deps.edn effectively reduces things down to a) what should be on the classpath and b) what should get executed. Working inside an IDE? You just want it to download the dependencies and build a classpath. Running nREPL? Add that to the classpath, and set the starting namespace to start nREPL. Packaging an application? Run dependencies that do that work, based on the clojure.tools.build library.
I was there myself; I used Leiningen and didn't take the time to figure out deps.edn --- until I did, saw the light, and converted all of Walmart's projects to use deps.edn, which greatly sped up our build and improved our dev experience.
Many people still use lein for new projects, especially for larger ones. For small on-off thing, clojure command line is more convenient. So it is a good thing to have more choices.
For a team that needs to get s** done and has more per employee productivity than Faang combined it's hard to beat the speed with which you can build things when you have the repl and interactive programming.
The jvm while doesn't have great error messages is a fantastic runtime.
Without it it’s a matter of time before the codebase can’t be developed anymore and the software doesn’t work as intended.
the fact that because of the repl the happy path is always tested while being built and with clojure spec you can secure the edges, it is quite scalable.
i love static typing and rust in general but with web applications, the problem space is really a distributed concurrency problem of dynamic data. and clojure is basically tailor made for that.
Pointers and null values are inescapable in go, and people treat them worse than they do in C. Generics are too limited (I can’t define a scala flatmap like function) And I can’t make data immutable or control access in any fine grained way in go. Compile time in my go monorepo is minutes now. Someone added a bunch of go lint rules.
Being simple is not a good thing. A simple language means that the programs become complex and hence complicated. The advantage is that it's easy to get up to speed and to write greenfield code though.
This is how I use Python to be honest. If I'm unsure of something, I just bust out the REPL.
I do not know how you do that in python without using a debugger and stepping through the code line by line. To be fair I used Python only a little bit almost a decade back. Are things more interactive now?
Currently https://clojuredocs.org is sort of the go to place. It wins due to Google algorithm.
I wanted to add the ability to vote on answers provided there. So that you have the ability to see the most relevant/popular answer, rather than the oldest.
Raised an issue on the repo, four years ago now. No response:
https://github.com/zk/clojuredocs/issues/222
And why do I mention Google algorithm? Because there was another effort that tried to create a (debatably) nicer documentation, but due to lack of Google traffic, it died. See: https://news.ycombinator.com/item?id=8027119
For a more eloquent argument on its uses, see this blog post:
https://metaredux.com/posts/2019/06/29/farewell-grimoire.htm...
If you can get past the serviceable UI then it's coding nirvana literally looking inside the program
Pair that with a good test suite so you can trigger lots of different scenarios and you're in heaven
But he could have been using F#, OCaml, Haskell. So it might not be just about pure functions and immutable data.
https://youtu.be/nD-QHbRWcoM?si=yneAgMhk6NjTf9ZU
The video I remember when he was describing the origin was on 480i, I’ll try to find it
CIDER (the emacs IDE for Clojure) does a really good job of filtering the stack trace and presenting several views depending on what you care about. L
The only thing that really sucked is just the documentation. They are overly concise. You end up relying on non-official sources of documentation.
I see articles (like the one above) where people are sharing their excellent experience using the language as has been my experience over the years of using it.
A justification would be 'we hate this ugly thing, but we use it because it's cool', but that's not what I've been reading..
There is a lot of elitism around Clojure and all of them are looking to throw down. Even your comment has already garnered 1 of them out of the shadows.
Justify using it against what? Can you name a single other language that does things better than Clojure? Not from your "point of values," but try seeing it from my position. Is there anything that can replace Clojure for me? I love the dynamism, malleability of the language - the flow; writing Clojure programs for me feels like playing a video game - it's plenty of fun. I don't get the same kicks from literally any other "mainstream-ish" language that's being used today. I like Common Lisp, but I have never had any practical, large opportunities to use it seriously, and there are things that I love in Clojure that I'm sure I'll miss in CL. I like Haskell, but it's even less practical (for me).
In my view, there isn't a single language that respects good ideas carried in Clojure and does them in a better or at least pragmatically viable fashion - I've evaluated Elixir, OCaml, Rust and some other choices. I am excited about Jank, can't wait for it to hit the first production-ready release. But today, nothing is more joyful for me to use than Clojure/Clojurescript.
Spec is still alpha and I’m not sure it will evolve more or if it’ll be something completely different. At least they’re not pushing you down the wrong path. Use/look at Malli instead of spec.
You can't just pass in a Clojure `fn` into a Java lambda function. You have to `reify` the interface and implement the single method. It's annoying and verbose and frustratingly the equivalent code is considerably cleaner in Java as a result.
I know that this is a product of how Java implemented lambdas by having interfaces with a single method, and I'm not saying that it would be trivial to add into Clojure, but I don't think it's impossible and I think people have been complaining about this for more than a decade now.
So while I love Clojure, it's probably my favorite language, I do get a little annoyed when people act like it's "stable" because there's nothing to fix.
No, but the release of spec single-handedly killed Schema, a more mature contract lib.
Then spec stagnated, because the core team didn't want to work on it, but as a core team library, nobody else can work on it, either.
Thus was born Malli, because people got tired of waiting.
I see the fact that there isn't much happening with the language as a positive myself. I want the core language to be small and stable. The big difference with Clojure and most languages is that it makes it far easier to implement new semantics in user space. It has a powerful macro system and new ideas can be expressed using libraries instead of having to be baked into the core language itself.
Most language grow through accretion as usage patterns change over time. New end up features end up getting bolted on to facilitate that, and the language keeps growing. The problem here is that the scope of things people have to know keeps growing as a result.
Meanwhile, Clojure managed to stay small and focused, while different kinds of ideas are expressed using libraries. When a new idea comes along people can just use a new library, and they don't have to learn about all the previous libraries that worked differently. I think this is a huge benefit from user perspective.
I mean, Datomic is free to use!
[core.async.flow]: https://github.com/clojure/core.async/commit/03b97e0b3e0ec32...
Additionally, while the growing number of compile targets in the Clojure ecosystem is impressive, it can also create confusion for newcomers. Whether it's compiling to native code with Jank, generating quick script snippets with Babashka, or using subsets of ClojureScript like sci or cherry, the diversity is both a strength and a challenge. I believe a concerted effort to unify configurations across these targets would help streamline the ecosystem and make it easier for developers to choose the right tool for their needs.
Also yeah, I agree that Babashka is a delight. I've been using it to manage a Caddy server via Caddy's JSON API and it worked great, super flexible.
FWIW, it works for me — I would not have been able to build and run my business without Clojure. The long-term stability is an especially important trait, under-appreciated by people who do not have a business to run.
Point of my sarcasm here is: you guys invoke them by yourself by writing overly defensive or overly religious posts. Then there will be ofc some critics, as with everything: they do not necessarily express a deliberate scheme against Clojure world. They are just some folks with different opinions, and also: very often wrong ones. But, as an advocate, please don't go into an offended teenager mode, when all the world plots against you; because a lot of rhetoric around defending Clojure sounds like that.
Another is that I get paid to work with distributed systems and databases, and Clojure isn’t even part of the discussion in that sphere. Go, Rust, and the usual Python and Node dominate there, so it’s hard for me to care.
However, I dislike language monoculture and am curious about why people like the things I might not care about. This blog is for those.
I now think of Clojure as a power tool for small shops and consultants. These aren't the kind of places that typically cast a wide net looking for "employees." Most of the opportunities are maybe more focused on proving that you can bring in business and network effectively enough to be a known quantity in the Clojure community.
I worked with Clojure/ClojureScript (mostly ClojureScript) for a couple of years many years ago. It was the first time I'd worked professionally with a functional language, so I made a game of minesweeper in my free time to help get to grips with it: https://github.com/robjinman/cljsmines
Back then, I fully bought into the idea that functional language like Clojure were the future, especially on the web. The way application state is managed is perhaps the key virtue of functional programming - if you get it right, you can design your program to consist mostly of completely pure functions. I remember how enlightening that was once I understood it.
Oh well, I forgot: how to use with TailwindCSS 4? What incantation of build system do I have to configure for live-reloading when classNames changes?
Sorry for the rambling. Just a poor confused user.
This is probably not the easiest "framework" (not sure this is a good name for it) but it was very fun. I think, if I had to progress from just a toy to a really strong, user facing UI, I think it would still be a pretty good choice. If some feature is missing, or something doesn't work as I would have liked, I know it will not be difficult to correct it myself.
I know that this could feel overwhelming, but this is freedom in a world where you expect there exists a single "best practice". As long as the tool is powerful enough it will be fine. On my end, I appreciate the fact there is not a single "web framework" in Clojure. Instead you have tons of libs you can use that work well together because they are all tied with a few common concepts (like ring for example). If you don't like to choose the libs. There are a few people that provide a starter pack with somewhat nice bundle of libs in a single system like pedestal or luminus for only citing two of them.
My recommendation is to not lose too much time looking for the best choice. Most of them will be good.
I wonder what would happen if someone adds a REPL to F#. Sure, it wouldn't have dynamic typing, but isn't static typing good for large code bases?
In particular, judging from the article and comments, it seems that the major boon is having an REPL integrated in the IDE, running in the background, so you can have feedback while you are writing the code.
Having such an integrated REPL for a language like Python would make the productivity up to par with Clojure?
I am trying to understand if Clojure has a particular feature other languages can't add with ease.
1. Syntax. It's a bit easier to just evaluate a symbolic expression (put in a simplified manner: anything enclosed by parentheses) than to select a region of Python code to evaluate. But it's no major issue. Don't know about any syntax that has similar properties, Ruby seems to be somewhat similar in spirit, every expression returning an object. Python OTOH has all kinds of constructs you can't evaluate readily.
2. Functional code. Lisp code is generally largely side effect free, Python is not. That goes from the libraries down to how you write your own code by convention. Evaluating code without side effects for quick feedback is a breeze. For side effect riddled code, it's kinda easier to just use unit tests with mocks etc. for that. There are lots of languages with good functional libraries nowadays.
Generally speaking, the things you list are what used to be unique about Lisp. But apart from the two points I'm making, I don't believe that's the case anymore. Lots of languages got inspired in the last few decades. I love Lisps and I wish I could use them more, but I'm happy lots of popular languages got reasonably close.
F# does, in fact, have REPL and excellent one at that!
There is F# interactive and F# scripting. It's my workhorse for all sorts of automation and quick "analyze data and draw a chart" style of one-off scripts. It's vastly superior experience because when editing F# scripts you get full LSP, ability to reference nuget packages without vendoring anything, etc etc.
Gradual typing and full type inference make it look at times like dynamically typed language but it's anything but and gives really nice user experience.
https://learn.microsoft.com/en-us/dotnet/fsharp/tools/fsharp...
Sometimes I just need to get some code running to see a result, which is my main use case for Lisp.
I used to default to Common Lisp, but it needs a lot of scaffolding to become ergonomic, and even then it has too many quirks to be really enjoyable for me.
So I started designing my own:
I mean, you have to try really hard to cultivate a community of people who have a deep love for something, but for some reason can't see what is actually wrong with it that drives ppl away. Passionate users are usually a boon, but apparently not for Clojure. But people somehow seem to build great companies with it. It's strange, and very specific to Clojure culture. I can't help but assume its failure to capture market is tightly tied to its leadership style and/or leader worship.
Anyhow, these are just hot-takes from the margins. I'm sure that passionate users will have something to say, or maybe downvote me.
After all, an elitist can also sometimes be right.
Disclosure: I say this as someone who has been about as deep as you can go in the Clojure community.
I really like this framing of "in tension". Multiple things can be true. I think it represents a healthy tension that I'm grateful exists, even if I'd not personally wish to be operating in that specific tension. But I'm sure the people living in are different than me, and can do things in this world that I could not :)
It's a large part of why I've stepped back from clj these days.
Did you encounter some hostility?
Elm is another example
How was your experience in working with the existing Clojure codebase?
The codebase was democracy-related civic tech software. I was a bit biased against Clojure because I wished for the world to show up in the codebase, but it was written in an uncommon language that scared away most every coder who showed up with curiosity.
Probably just the wrong language for the culture I wished to exist around the software. Plus the maintainers used Rich's essays to emphasize their desired ethos of "singular vision" development, which I admittedly became resentful of.
The biggest problem I had (and still have) with Clojure is that, even in its heyday (circa 2014-2018 or so) I couldn't convince people to keep using it. It seemed like every smart, senior engineer I knew tried it, loved it, wrote load-bearing stuff in it, and then walked away: either abandoned it at their companies, abandoned it for personal projects, or started companies using other languages instead of Clojure. And this was when Clojure was hot shit. Big Data was all the rage, and everyone had heard of or was using Storm. Clojure was the language.
You might counter that maybe me or the people I know are fools, not smart enough for Clojure, or picked stupid languages for the wrong reasons, or followed the crowd, or whatever else. And you might be right!
But all I know is that the smartest people I know tried Clojure, learned it, respected it, learned a ton from Rich about how to think about systems, and ultimately walked away, because they were, variously, repelled by what they perceived as:
- the elitism in the community
- the elitism in the core team
- the impenetrability of the tooling and the unwillingness of anyone to admit that it sucked
- the sometimes not so subtle denigration of their skills as professionals for having the audacity to, for example, use web frameworks rather than build everything from scratch
I bring this up because for me programming is social. I love being able to write code that does something fun and/or useful and tickles that part of my brain that loves expressing what I want in a beautiful way, but ultimately it's more useful to be to be able to write code that my friends and colleagues can understand and are willing to use.So I have to wonder, is it sustainable for a community to be as reliant on true believers as Clojure seems to be? Is it sustainable to alienate as many of those folks who maybe aren't true believers, but who would love using it anyway? Who knows, maybe it is! But I can tell you: I'm Clojure's audience, and I don't use Clojure today, and none of my now-Staff and Principal and CTO level friends are using it or teaching it to the juniors on their teams or choosing it for their companies. Why? Wouldn't it be better if we were?
> "But what about hiring?" When you use any language that isn't in the top 3 of currently most popular languages, you will get this question. JavaScript programmers are counted in the millions, Clojure programmers in the tens of thousands. How will you ever find the required talent?
is it just me or i, for the love of whatever that is holy, find that fp related jobs are so few and far in between? not only clojure, but also f#, haskell, etc? to be honest, fam, if you want to sell a language or two, at least make it possible for people to make a living in it. sorry to say, mate, but my kids can't eat a "lovely" niche programming language.
p.s., i actually have some working exp. in haskell yet nobody approached me because of it.
Clojure sort of guides you to simplicity, building everything out of functions and simple datastructures has big advantages when testing and reasoning about code.
I do find that in larger code bases, Clojure lack of types causes friction (spec is just a bandaid, not a fix).
There are languages with immutability and types (like Haskell), but these don't have the get-shit-done factor I seek.
OK.
> Thanks for the segway.
A segway is a motorized transport; a segue is a transition to a different topic. So this could be considered a type error, and demonstrates why you need types, not just immutability.
Interestingly, most of the low level libraries in the Clojure ecosystem are programmed that way. If you open up the code of many popular Clojure libraries, you see defprotocol everywhere.
So really, Clojure does both: dynamic typing for application programming, mostly static typing for infrastructure library code. As they should be.
This tired argument of "Clojure bad for dynamic typing" just doesn't hold water. Keep repeating it is a sign of lack of critical thinking.
Coders often accept the status-quo of things - "So what that we can't easily upgrade our dependencies in our Node/Ruby/Python project - it's a known thing, we just have to deal with it..."; "Of course our builds take 90 minutes, that's normal for a big project"; "We need complex state management like Redux"; "Code must be recompiled after every change"; "Testing requires mocking everything", "Type safety prevents runtime bugs"; etc.
Yet, when it comes to actual work, not some cheap talking points but real, practical scenarios - there aren't many other tools that can beat Clojure for robustness, pragmatism, and speed of building things with it.
Most experienced Clojuristas are incredibly knowledgeable, skilled, and seasoned programmers, architects, and system designers who are passionate about their craft, using tools, techniques and patterns that enable them to perfect it while remaining pragmatic and grounded. But hey, don't blindly trust my word, go see for yourself - open ClojureTV YT channel, watch their presentations and draw your own conclusions.
Very few languages still in use in the modern era are still weakly-typed.
My personal take is that while a lot of type systems can be overblown, nil-punning is not a sufficient substitute for optional/maybe types.