Clojure has a dirty little secret

There’s been a lot of talk about Clojure adoption lately…

I want to put something out there about that subject.

Clojure is the easiest language.

There, I said it.

I haven’t wanted to say it for years. Secretly, when other people said Clojure was hard, it made me feel superior - like I was special because I “knew” Clojure. And, with Clojure being a nascent up-and-comer, I didn’t want to give people the impression that Clojure was some toy language like Python, for beginners.

But that was a lie. Clojure is the best beginner’s language because it’s the easiest language. Literally and objectively.

And, with all the progress Clojure has made - hell, we’re the best paid programmers in the industry! - I feel like Clojure has “made it” and we no longer need to hide Clojure’s secret. We have to stop acknowledging the argument that “yeah, the parens are hard at first.” It’s just not true. They’re not. There’s literally nothing hard about Clojure. Sure, being a “hosted” language makes things a little more complex, but you can stick to the core language as a beginner and it will be easier to learn than any other language. I know, because I came to Clojure as a beginner and the only reason I got hooked was because it was easier. I’m lazy like that - I like easy, that’s my secret - and Clojure makes hard things easy.

We shouldn’t be afraid to be honest about that. Not anymore. Clojure is more “scriptable” than any scripting language in existence. Maybe we’re afraid that our “highest pay in the industry” will go down if the secret gets out. Maybe we’re afraid people won’t think we’re magicians anymore. But if Clojure is going to grow beyond the magician class, people need to know - Clojure is actually the easiest language. It’s just true.

I know - “Simple ain’t easy.” But that war was won (by Rich and others). It’s easy now. Almost too easy, it’s ridiculous what we can accomplish with such ease. Sharp tools and special instruments, blah blah, sure. We have those. But Clojure is the most general purpose, forgiving, easy language you can wield to get anything done. It’s the hammer, not the chisel. Sure, you can chisel with it, which is great. But the best part about it is that, in the general case, it’s the easiest, biggest hammer around.

Thankfully, Clojure is versatile enough that it can achieve production level performance - in fact, you can achieve anything, and that part can be hard, but at least you can achieve it. 99% of your problems are not those hard problems though. And for those common problems, using any other language is like trying to swim up stream - in the long run, you’re just making things harder for yourself. That’s our dirty little secret that we’re not being honest enough about. Perhaps out of pride.

I think it’s time we let the cat out of the bag.

Clojure is the easiest language. Period. Let’s stop pretending it’s not.

20 Likes

I dunno how to respond to this… so I did a copy paste, replaced ‘clojure’ with ‘bitcoin’, ‘Python’ with ‘NFTs’, ‘language’ with ‘financial’ instrument, and ‘Rich’ with ‘satoshi’.

It actually reads okay.


There’s been a lot of talk about bitcoin adoption lately…

I want to put something out there about that subject.

bitcoin is the easiest financial instrument.

There, I said it.

I haven’t wanted to say it for years. Secretly, when other people said bitcoin was hard, it made me feel superior - like I was special because I “knew” bitcoin. And, with bitcoin being a nascent up-and-comer, I didn’t want to give people the impression that bitcoin was some toy financial instrument like NFTs, for beginners.

But that was a lie. bitcoin is the best beginner’s financial instrument because it’s the easiest financial instrument. Literally and objectively.

And, with all the progress bitcoin has made - hell, we’re the best paid programmers in the industry! - I feel like bitcoin has “made it” and we no longer need to hide bitcoin’s secret. We have to stop acknowledging the argument that “yeah, the parens are hard at first.” It’s just not true. They’re not. There’s literally nothing hard about bitcoin. Sure, being a “hosted” financial instrument makes things a little more complex, but you can stick to the core financial instrument as a beginner and it will be easier to learn than any other financial instrument. I know, because I came to bitcoin as a beginner and the only reason I got hooked was because it was easier. I’m lazy like that - I like easy, that’s my secret - and bitcoin makes hard things easy.

We shouldn’t be afraid to be honest about that. Not anymore. bitcoin is more “scriptable” than any scripting financial instrument in existence. Maybe we’re afraid that our “highest pay in the industry” will go down if the secret gets out. Maybe we’re afraid people won’t think we’re magicians anymore. But if bitcoin is going to grow beyond the magician class, people need to know - bitcoin is actually the easiest financial instrument. It’s just true.

I know - “Simple ain’t easy.” But that war was won (by satoshi and others). It’s easy now. Almost too easy, it’s ridiculous what we can accomplish with such ease. Sharp tools and special instruments, blah blah, sure. We have those. But bitcoin is the most general purpose, forgiving, easy financial instrument you can wield to get anything done. It’s the hammer, not the chisel. Sure, you can chisel with it, which is great. But the best part about it is that, in the general case, it’s the easiest, biggest hammer around.

Thankfully, bitcoin is versatile enough that it can achieve production level performance - in fact, you can achieve anything, and that part can be hard, but at least you can achieve it. 99% of your problems are not those hard problems though. And for those common problems, using any other financial instrument is like trying to swim up stream - in the long run, you’re just making things harder for yourself. That’s our dirty little secret that we’re not being honest enough about. Perhaps out of pride.

I think it’s time we let the cat out of the bag.

bitcoin is the easiest financial instrument. Period. Let’s stop pretending it’s not.

1 Like

It sounds like you’re trying to say that Clojure’s easiness is not actually objective and I can appreciate that sentiment. But I’ve been thinking about this for a few years and I think we can make the case objectively.

Algol based languages took a wrong turn. They tried to make computer languages more like spoken language, with a mix of infix and, sotospeak, outfix (blah.blah(stuff)) notation, which actually put more distance and friction between the programmer and the solution.

Algo based languages are a parochiality of human language syntax. It turns out, it’s better to approach human level abstractions in computers with just compositions of verbs and nouns, not syntactic anachronisms of human parts of speech. They’re superfluous to the computer domain and make it harder to reduce over and map to the computer domain. Every algo-based language ends up being is own special snowflake that introduces unnecessary syntactic jargon that, in the long run, just conflates human syntax solutions with computer solutions - it’s just unnecessary baggage that makes everything harder to understand and use in the end.

Otherwise, I agree, it’s all just lipstick over the same pig.

4 Likes

That and persistent data structures make concurrency/parallelism easier… along with some other things that make things easier… There’s a few places where Clojure is harder than most and a number of other places where Clojure is easier than most. On the whole, I think it makes hard things easier compared to other languages. But in the main, I think all those algol (hey look, I’m like a human language) languages are snake oil when comes to easiness.

2 Likes

Glad you didn’t take it the wrong way. And appreciate the work you did with shared workers btw.

  • Clojure is pretty difficult to learn if your only other reference is coming from ANY other language that allows mutation. One has to pretty much relearn everything from the beginning in terms of algorithms. When I got started. It WAS hard.

  • When I got started, clojure was exciting and there were new libraries coming out all the time. People were experimenting with paradigm shifts - especially in the area of language design and it was great to learn and participate in that environment. I don’t think this is the case anymore and to me, it’s not a good sign.

  • Maybe everything about programming has been invented and we can all bask in the fact that ‘the war is over’. Most of the time it’s too early to well. But history has never been a friend of hubris.

2 Likes

I think that’s not an intrinsic difficulty though. I think being familiar with one paradigm creates a difficulty-bias that one can’t recognize. If one is unfamiliar with both paradigms, which one is actually easier? There’s mutable algorithms out there that are way more complicated than immutable ones. Immutable algorithms seem like a more simplistic subset, which can take some relearning if you’ve already learned mutable ones. And I think mutability can be a good weapon to have, but not necessarily easier, especially when used gratuitously.

When I got started, clojure was exciting and there were new libraries coming out all the time. People were experimenting with paradigm shifts - especially in the area of language design and it was great to learn and participate in that environment. I don’t think this is the case anymore and to me, it’s not a good sign.

Yeah, good times :slight_smile: In some ways things have matured though. Lots of lang/tech communities were more campy and cliquish and fun back then, before the rest of the world moved onto the internet - many highly social tech groups have become less social as the rest of the world has become more internet-social I think. I don’t think it’s a Clojure thing necessarily. We do need to foster more of that old excitement though.

Maybe everything about programming has been invented and we can all bask in the fact that ‘the war is over’. Most of the time it’s too early to well. But history has never been a friend of hubris.

In terms of mindshare, the war has just begun! :slight_smile: I just think we should stop acting like (or letting others act like) Clojure is “hard” when it’s actually, I think, the easiest language out there, by many standards of measure that actually matter.

Thanks for your contributions to the ecosystem as well! I’ve learned a lot from your code. And I appreciate your challenging me and others as well. slaps zcaudate with a dead fish

2 Likes

ah… the good old days.

1 Like

I get what you are saying and totally agree. Once familiarised, there are certain benefits for using an immutable model. However, there are also penalties for using an immutable model too, not to mention an immutable model that is hosted on the jvm. Furthermore, the immutable model is built on a mutable one (it’s just hidden) the immutability is not free. That 99% argument does apply but you will not see google or microsoft/bing implementing their bloom filters with clojure. So for the 1% of the hard performance orientated problems (which probably affects 80-90% of the performance of the system), clojure is completely out of the question.

There is too much of a batteries included mindset right now. There’s just too much there in clojure.core and a lot of the internals are extremely dependent on the JVM. Yes, there are ports but there is no standard which simpler languages such as c, lua, and scheme provide that enable the proliferation of the language in all sorts of places. Every implementation of clojure has its own quirks. Code written for one will probably fail on another, even in cljs unless one uses those really ugly macros that remind me of the C Preprocessor.

I would argue that the most scriptable language in the world is lua. Because it actually is - GitHub - LewisJEllis/awesome-lua: A curated list of quality Lua packages and resources.. Why? Because lua is simple to embed and its proliferation is evidence of that.


There are definite uses for the immutable model, which is why clojure is one of the best languages to build compilers with. Compilers should be build on immutable data. That’s a real solid use case. But I don’t see many people doing that anymore - at least in the open source space.

1 Like

I do wonder if creating more of a reputation for being easy in turn makes it feel easier to people.

Easy is a feeling, maybe your expectations from what you’ve read or were told play into that feeling.

I also think familiarity is a big part of being easy, you’ve already learned most of it if you’re familiar with it already.

I’ve got no idea if Greek is easy or not, but learning Spanish if you speak French is easier, since you’ve got a lot of familiarity with it already. Going from English to Spanish might be harder.

I think easy also comes from mainstream popularity, better guides, more mentors, better done YouTube videos, more examples, that all help make things easier.

And the problems about mutability don’t make it hard, people simply ignore all the bugs and still release their app to prod :stuck_out_tongue_closed_eyes: Now writing correct mutable programs, nobody’s ever figured it out.

I’ve never found Clojure hard, I’d agree with you on it being easy, or at least it’s simple, and that makes it easier for me. The issue is when someone is struggling with it, if I tell them it’s easy, they take it as a personal insult, then they’ll say, look I know C++, I know Java, I have 30 year experience with OOP, I know C#, I’ve build many enterprise systems, I know Spring, I know Python, I can figure out how to do this in Python in a breeze, etc. Basically they can take it as a judgement of their qualities, I don’t know why it’s hard for them, but when someone finds something hard, telling them it’s easy doesn’t help, maybe a minor form of gaslighting… Then again, maybe it does help in a machiavelic way :thinking:, anger motivation, I’ll show you motivation?

But then I go back to that main point, maybe people find Python hard too, but don’t say it, because everyone knows it’s easy, can’t possibly find it hard.

I’ve also noticed that Clojure is an easy scapegoat, this took me longer because of Clojure, my startup failed because of Clojure, I couldn’t complete my story because of Clojure. Yet when you use Java, everything is broken, complicated and takes longer all the time. But nobody blames Java, then it’s a bad code base, it’s bad decisions, it’s bad design, it’s a complex use case, it’s legacy systems, it’s junior programmers who didn’t know better, etc.

Imagine a founder saying their startup failed because of Java? People would laugh, you know how many things are Java out there, you can’t use popular things as scapegoat, people won’t believe you. But Clojure is a great target for that.

4 Likes

Also, if you really want mutability - it’s easier to write Java in Clojure than Java :smile:

And I’d rather write Javascript in Clojurescript than Javascript. Can someone remind me what this string of Javascript means? protected abstract blah(): string; What other keywords can I stack between protected and abstract? In what scopes is that allowed? Does anyone know? Ambiguous rules around keyword stacking and what expressions are allowed after them, just to make it seem like it’s an English sentence, is an anti-pattern. You end up with a thousand little languages within your langage and you have to learn each one. And writing transformations over those expressions becomes a PhD dissertation - again, pushing the programmer further from possible solutions. All for what? The false pretense of looking like a sentence.

Again, mutability is just as easy in Clojure as in other languages. It acknowledges, contrary to popular opinion, immutability is actually the big hammer and mutability is really the sharp footgun that you should use more sparingly, if you want your life to be easier.

1 Like

As someone who was heavily involved in ClojureBridge in the early days, I can say that complete beginners tended to do pretty well learning Clojure in a day, but folks who had a background in OOP sometimes struggled – and I’ve seen that carry over into the broader “Clojure beginner” audience over the years as more people have come into our community.

As @didibus says, we need to be a bit careful about the word “easy” because it can be very “loaded”. It’s why you should be careful not to respond to a beginner’s question with “just” or “trivial” – or even things like “you simply do XYZ”. They can make the beginner feel inadequate and that they are being talked down to. Unfortunately, it’s also why we need to be a bit careful about “simple” too. Telling someone who is struggling to learn Clojure that it is “simple” is often heard as “it is easy” and, again, that’s not what they need to hear – especially if they haven’t watched and internalized Rich’s simple vs easy talks!

As someone who has learned a lot of languages over a forty-plus-year career, I can say objectively that Clojure is one of the simplest languages to learn because it’s a very small language (core) with consistent abstractions and idioms. It may or may not be “easy” for any given individual.

8 Likes

I think thats kind of silly. how do you think clojure got made?

i’ve never heard anyone complain about their startup failure because of language choice. usually, they would rather die by that hill - myself included. people? yes, investors? yes, languages? give me a break.

what i have heard however is 'we would have loved to use X clojure product for or system, however after extended trials, and sometimes asking for help from X clojure company, we had to resort to Y because of Z reasons.

and you know what, it did upset me at that time hearing that at the time because i just thought that the guy i was working for at the time was a smug asshole that didnt truly understand clojure.

well… how the turntables.

people confuse developer mindshare and consumer mindshare. believe it or now, as programmers only apart from a few people here on the forum who can truly influence the direction of the language. the rest of us are clojure consumers. me being a very happy one at that. so i would label myself as a consumer of clojure. developer mindshare is influenced by platforms not languages. people write solidity because they want to build on the blockchain, not the other way around. I chose clojure because I saw it as a relatively risk free small jump from an OO paradigm. It was and still is a great choice.

looking to understand strengths and weaknesses of a tool that one works with everyday is a valued trait that I look for in the people that I work with. Id rather the actual truth upfront than the shrug and fingerpointing after 6 months of ‘development’.

We should really admit this about ourselfs… none of us really know what we’re doing and it’s okay.

I’ve actually heard that from some of the smartest minds in the industry, “nobody actually knows what they’re doing.”

What seems clear though is that most languages, including JavaScript, are starting to adopt immutable practices and algorithms. Probably because it’s easier to maintain those code bases. But nothing makes that easier than Clojure. In 2030, they’ll all have Clojure idioms, just not originally built for them.

To be fair, we’ve been seeing other languages adopt “Lispisms” for decades and then “FPisms” for maybe a decade – so, sure, you can say they’re adopting “Clojurisms” but you’re not being entirely honest with yourself :smile:

I think Clojure is the best language we have today, in terms of design. But language design continues to evolve.

3 Likes

I don’t think that’s exactly true… especially if immutable is not the default.

Firstly, UI engineering is very performance orientated. Usually we think about web with clojure ui. When om first came out, one of the devs from the react team saw the om blog post and put his own spin on it → redux. And it really blew up. However, having state controlled in one spot and having your whole application react around that state may not be the best option, especially if something or a number of things have to change extremely quickly. When you add in the cost of creating immutable datastructures… that may be the thing that is impacting performance → say when you want to drive animations.

The more natural model for ui is still an eventing model and you can see the entire js ecosystem move towards that with solidjs, sveltejs and a whole bunch of react wannabes. With immutablejs, I believe hype is waning for that as well. Within react, immerjs offers a more compelling solution than straight up immutable datastructures. But even so, I still think it’s too heavy handed. I actually prefer GitHub - pmndrs/valtio: 💊 Valtio makes proxy-state simple for React and Vanilla and other libraries by Poimandres.

Even within cljs itself, there’s a move away from the heavier components to compiling straight to jsx with GitHub - pitch-io/uix: Idiomatic ClojureScript interface to modern React.js and GitHub - lilactown/helix: A simple, easy to use library for React development in ClojureScript.. These libraries are good solid use cases of clojure as a compiler that I spoke of previously - honeysql and venia(graphql) being other examples.

Games are another matter completely. Tools for games may be built in clojure, but the final product will not be in the language. For people that actually care about performance, cljs and ui libraries based off of immutable datastructures are not particularly attractive.


The server side is a bit more compelling but start up speed is definitely an issue these days, along with the memory consumption. That’s why you do see clojure people jumping into Janet - https://joy.swlkr.com because it’s more cost effective to deploy applications this way. Cost is actually an issue. There’s always babashka but no one is serious enough to build something like a datacenter on babashka.


Clojure absolutely has had a huge effect in the development of modern languages but the world goes on.

1 Like

There’s currently a proposal to introduce immutable datastructures to JS: GitHub - tc39/proposal-record-tuple: ECMAScript proposal for the Record and Tuple value types. | Stage 2: it will change!

Some of the proposed performance benefits:

Optimizations for making deep equality checks fast:

  • For returning true quickly, intern (“hash-cons”) some data structures
  • For returning false quickly, maintain a hash of the tree of the contents of some structures

Optimizations for manipulating data structures:

  • In some cases, reuse existing data structures (e.g., when manipulated with object spread), similar to ropes or typical implementations of functional data structures
  • In other cases, as determined by the engine, use a flat representation like existing JavaScript object implementations

But the biggest reason they argue for them is to reduce cognitive burden - because some things in JS shouldn’t be so hard. The equality semantics that persistent datastructures afford make your life easier.

Regarding re-frame/redux - you don’t have to use a single global atom… But using component local state everywhere is going to make your life hard. Using a combination of the two is the ideal medium IMO, which is easy in CLJS world. WRT to the new thin react wrappers, I like how they make it easier for JS devs to move to CLJS, but they don’t excite me as much. They carry over too many react constraints because of JS’s everything-is-mud world.

But you don’t have to use react at all - shadow-grove is closer to the svelte model, bypassing the vdom step. And you don’t have to use persistent data structures everywhere. If we see a hot loop where an array can be transparently swapped in, and it won’t affect any outside consumers, we sometimes do that. But that’s for an expert to do, sparingly and only when it actually helps. For the other 99% of problems, most people can just use the immutable API. That’s the point. When things are pure at the API level (persistent data structure or not), everything is easier for the user, be they an expert or a beginner.

And I personally don’t see many enterprises complaining about Clojure startup time. For lambdas, sure, but most folks don’t run 90% of their business on lambdas - it’s usually for hooks and things that aren’t used often. Nor memory consumption. I personally don’t think Clojure is “expensive” when it comes to memory. It’s well worth the cost in maintainability and malleability.

I think most of the complaints around performance, memory and startup time around Clojure are just excuses to not address other problems. For performance, again, you can do mutability in Clojure, and it’s just as dangerously fast inside the parenthesis as it is outside. For memory and startup, again, the vast majority of products and services aren’t constrained by Clojure’s profile there, and they’re really not that bad.

The single biggest difficulty is there not being enough Clojure devs out there yet. One step on the way to fixing that problem is for people to abandon this notion that Clojure is “hard.” The truth is not using Clojure is hard. Or, as @seancorfield points out, not using FP is hard. But Clojure makes that uniquely easy.

1 Like

Didn’t know about the proposal. It’s definitely clojure inspired. But the flip side will be that if it does become standard, cljs will have to evolve or become irrelevant.

Didn’t know about shadow-grove but it sounds like it’s going in the right direction. I don’t really understand the compilation approach but unless there’s a decent enough transpiler to convert react code to svelte/shadow-grove, legacy systems will still be react based. There’s just way too much react code out there right now for it to go away.

Performance, memory and startup time are pretty important problems related to how much a system can scale. For example, if a system memory needed 8Gb to run properly and that can be somehow reduced to 1Gb, it’s an 8x saving. If it’s reduced to 100Mb, it’s an 80x.

Yeah, that’s probably true for a certain set of domains, but I think it’s a very narrow set. Embedded, resource constrained scenarios. And maybe some domains where you’re just reinventing the same wheel for the upteenth time, but just a bit faster than your competitor, sure. I would like to see a optional-GC Clojure version one day for those spaces. But when you are trying to innovate and create something new, from a business perspective, you don’t want to be in the bit twiddling game. You want a codebase that can change quick while still having very reliable semantics for both experts and beginners.

I agree the react ecosystem will be around for a good while. I’d love to try shadow-grove on some greenfield thing soon though.

That’s definitely key to maintainability.

Please do.

My comment was mostly thong in cheek, even though it harbors some truth, mutability brings additional classes of defects that are eliminated without. Like everything in software, especially because of hardware constraints, there’s trade-offs to be made, if it weren’t for those, I think semantically most people would adopt immutable variants.

I’ve definitely been burned a few times by hard to debug mutability bugs, they’re hard to catch and hard to fix. The reason is that they’re counterintuitive, normally when you’re holding something in your hands, you don’t expect other people are also somehow secretly able to modify what you’re holding. So as you work on it, you assume you’re exclusively in charge.

I think this happens in the code as well, pass something to a function, you don’t expect that on the next line of code it secretly got changed.

Modify some variable, you don’t expect that some other context in between your changes will also change it.

There’s also the place orientedness, I was sure this thing was supposed to be at index 3, what happened? The code locality doesn’t match the data locality, so some code in a different file or even different code base altogether you were relying on to have ahead of you looking for it, put some data at some specific place, why isn’t it there? Or why isn’t it in the structure and shape you expect?

There’s more I’m forgetting probably, like value semantics for equality, this is much more natural, are these two lists or maps equal? It’s more intuitive that they are if they have equal value. You have to remember that’s not the case in mutable world, which if you forget can be another cause for bugs.

All these make mutability harder to work with. But it’s not that immutability doesn’t have downsides, performance and memory use is the big one, but also ergonomics of immutability forces a different code style, and for some problems it’s tricky as well. Carrying over past data you will need later can be a bit more cumbersome to implement than storing the data in some array cache and referring to previous data by index relative to the current index.

Think dynamic programming for example, you want to know, what was the result of the computations done 3 iterations prior? If as you iterate you have to pass to the next iteration a lingering copy of x iterations, that’s often more work to implement than putting each pass at array[i] and then looking at i - 3.

That said, in general, I’m convinced immutable is the better default, and reaching for mutability when you either need the performance or memory improvements, or are in those rare scenarios like of a dynamic programming implementation that is easier to code in a mutable style.

1 Like