Immutability is also overrated. I mostly blame react for that. It has done a lot to push the idea that all state and model objects should be immutable. Immutability does have advantages in some contexts. But it's one tool. If that's your only hammer, you are missing other advantages.
The only benefit to mutability is efficiency. If you make immutability cheap, you almost never need mutability. When you do, it’s easy enough to expose mechanisms that bypass immutability. For instance in Clojure, all values are immutable by default. Sometimes, you really want more efficiency and Clojure provides its concept of “transients”[1] which allow for limited modification of structures where that’s helpful. But even then, Clojure enforces some discipline on the programmer and the expectation is that transient structures will be converted back to immutable (persistent) structures once the modifications are complete. In practice, there’s rarely a reason to use transients. I’ve written a lot of Clojure code for 15 years and only reached for it a couple of times.
Immutability is really valuable for most application logic, especially:
- State management
- Concurrency
- Testing
- Reasoning about code flow
Not a panacea, but calling it "overrated" usually means "I haven't felt its benefits yet" or "I'm optimizing for the wrong thing"
Also, experiencing immutability benefits in a mutable-first language can feel like 'meh'. In immutable-first languages - Clojure, Haskell, Elixir immutability feels like a superpower. In Javascript, it feels like a chore.
A lot of these concepts don't mean anything to most developers I've found. A lot of the time I struggle to get the guy I work with to compile and run his code. Even something relatively simple as determinism and pure functions just isn't happening.
This is shockingly common and most developers will never ever hear of Clojure, Haskell or Elixir.
I really feel there is like two completely different developer worlds. One where these things are discussed and the one I am in where I am hoping that I don't have to make a teams call to tell a guy "please can you make sure you actually run the code before making a PR" because my superiors won't can him.
> Not a panacea, but calling it "overrated" usually means "I haven't felt its benefits yet" or "I'm optimizing for the wrong thing"
I think immutability is good, and should be highly rated. Just not as highly rated as it is. I like immutable structures and use them frequently. However, I sometimes think the best solution is one that involves a mutable data structure, which is heresy in some circles. That's what I mean by over-rated.
Also, kind of unrelated, but "state management" is another term popularized by react. Almost all programming is state management. Early on, react had no good answer for making information available across a big component tree. So they came up with this idea called "state management" and said that react was not concerned with it. That's not a limitation of the framework see, it's just not part of the mission statement. That's "state management".
Almost every programming language has "state management" as part of its fundamental capabilities. And sometimes I think immutable structures are part of the best solution. Just not all the time.
> I like immutable structures and use them frequently.
Are you talking about immutable structures in Clojure(script)/Haskell/Elixir, or TS/JS? Because like I said - the difference in experience can be quite drastic. Especially in the context of state management. Mutable state is the source of many different bugs and frustration. Sometimes it feels that I don't even have to think of those in Clojure(script) - it's like the entire class of problems simply is non-existent.
Of the languages you listed, I've really only used TS/JS significantly. Years ago, I made a half-hearted attempt to learn Haskell, but got stuck on vocabulary early on. I don't have much energy to try again at the moment.
Anyway, regardless of the capabilities of the language, some things work better with mutable structures. Consider a histogram function. It takes a sequence of elements, and returns tuples of (element, count). I'm not aware of an immutable algorithm that can do that in O(n) like the trivial algorithm using a key-value map.
Try Clojure(script) - everything that felt confusing in Haskell becomes crystal clear, I promise.
> Consider a histogram function.
You can absolutely do this efficiently with immutable structures in Clojure, something like
(reduce (fn [acc x]
(update acc x (fn [v] (inc (or v 0)))))
{}
coll)
This is O(n) and uses immutable maps. The key insight: immutability in Clojure doesn't mean inefficiency. Each `update` returns a new map, but:
1. Persistent data structures share structure under the hood - they don't copy everything
2. The algorithmic complexity is the same as mutable approaches
3. You get thread-safety and easier reasoning for a bonus
In JS/TS, you'd need a mutable object - JS makes mutability efficient, so immutability feels awkward.
But Clojure's immutable structures are designed for this shit - they're not slow copies, they're efficient data structures optimized for functional programming.
> immutability in Clojure doesn't mean inefficiency.
You are still doing a gazillion allocations compared to:
for (let i = 0; i < data.length; i++) { hist[data[i]]++; }
But apart from that the mutable code in many cases is just much clearer compared to something like your fold above. Sometimes it's genuinely easier to assemble a data structure "as you go" instead of from the "bottom up" as in FP.
Sure, that’s faster. But do you really care? How big is your data? How many distinct things are you counting? What are their data types? All that matters. It’s easy to write a simple for-loop and say “It’s faster.” Most of the time, it doesn’t matter that much. When that’s the case, Clojure allows you to operate at a higher level with inherent thread safety. If you figure out that this particular code matters, then Clojure gives you the ability to optimize it, either with transients or by dropping down into Java interop where you have standard Java mutable arrays and other data structures at your disposal. When you use Java interop, you give up the safety of Clojure’s immutable data structures, but you can write code that is more optimized to your particular problem. I’ll be honest that I’ve never had to do that. But it’s nice to know that it’s there.
The allocation overhead rarely matters in practice - in some cases it does. For majority of "general-purpose" tasks like web-services, etc. it doesn't - GC is extremely fast; allocations are cheap on modern VMs.
The second point I don't even buy anymore - once you're used to `reduce`, it's equally (if not more) readable. Besides, in practice you don't typically use it - there are tons of helper functions in core library to deal with data, I'd probably use `(frequencies coll)` - I just didn't even mentioned it so it didn't feel like I'm cheating. One function call - still O(n), idiomatic, no reduce boilerplate, intent is crystal clear. Aggressively optimized under the hood and far more readable.
Let's not get into strawman olympics - I'm not selling snake oil. Clojure wasn't written in some garage by a grad student last week - it's a mature and battle-tested language endorsed by many renowned CS people, there are tons of companies using it in production. In the context of (im)mutability it clearly demonstrates incontestable, pragmatic benefits. Yes, of course, it's not a silver bullet, nothing is. There are legitimate cases where it's not a good choice, but you can argue that point pretty much about any tool.
If there was a language that didn't require pure and impure code to look different but still tracked mutability at the type level like the ST monad (so you can't call an impure function from a pure one) - so not Clojure - then that'd be perfect.
But as it stands immutability often feels like jumping through unnecessary hoops for little gain really.
There's no such thing as "perfect" for everyone and for every case.
> feels like jumping through unnecessary hoops for little gain really.
I dunno what you're talking about - Apple runs their payment backend; Walmart their billing system; Cisco their cybersec stack; Netflix their social data analysis; Nubank empowers entire Latin America - they all running Clojure, pushing massive amounts of data through it.
I suppose they just have shitload of money and can afford to go through "unnecessary hoops". But wait, why then tons of smaller startups running on Clojure, on Elixir? I guess they just don't know any better - stupid fucks.
But ok, if mutability is always worse, why not use a pure language then? No more cowardly swap! and transient data structures or sending messages back and forth like in Erlang.
But then you get to monads (otherwise you'd end up with Elm and I'd like to see Apple's payment backend written in Elm), monad transformers, arrows and the like and coincidentally that's when many Clojure programmers start whining about "jumping through unnecessary hoops" :D
Anyway, this was just a private observation I've reached after being an FP zealot for a decade, all is good, no need to convert me, Clojure is cool :)
Clojure is not "cool". Matter of fact, for a novice it may look distasteful, it really does. Ask anyone with a prior programming experience - Python, JS, Java to read some Clojure code for the first time and they start cringing.
What Clojure actually is - it is "down to earth PL", it values substance over marketing, prioritizes developers happiness in the long run - which comes in a spectrum; it doesn't pretend everyone wants the same thing. A junior can write useful code quickly, while someone who wants to dive into FP theory can. Both are first-class citizens.
One doesn't need to "wear a tie" to learn Clojure - syntax is so simple it can be explained on a napkin. You need to get:
1. An editor with structural editing features - google: "paredit vim/emacs/sublime/etc.", on VSCode - simply install Calva.
2. How to connect to the REPL. Calva has the quickstart guide or something like that.
3. How to eval commands in place. Don't type them directly into the REPL console! You can, but that's not how Lispers typically work. They examine the code as they navigate/edit it - in place. It feels like playing a game - very interactive.
That's all you need to know to begin with. VSCode's Calva is great to mess around it. Even if you don't use it (I don't), it's good for beginners.
Knowing Clojure comes super handy, even when you don't write any projects in it - it's one of the best tools to dissect some data - small and large. I don't even deal with json to inspect some curl results - I pipe them through borkdude/jet, then into babashka and in the REPL I can filter, group, sort, slice, dice, salt & pepper that shit, I can even throw some visualizations on top - it looks delicious; and it takes not even a minute to get there - if I type fast enough, I slash through it in seconds!
Honestly, Clojure feels to be the only no bullshit, no highfalutin, no hidden tricks language in my experience, and jeeeesus I've been through just a bit more than a few - starting with BASIC in my youth and Pascal and C in college; then Delphi, VB, then dotnet stuff - vb.net, c#, f#, java, ruby; all sorts of altjs shit - livescript, coffeescript, icedcoffeescript, gorillascript, fay, haste, ghcjs, typescript, haskell, python, lua, all sorts of Lisps; even some weird language where every operator was in Russian; damn, I've been trying to write some code for a good while. I'm stupid or something but even in years I just failed to find a perfect language to write perfect code - all of dem feel like they got made by some motherfluggin' annoyin' bilge-suckin' vexin' barnacle-brained galoots. Even my current pick of Clojure can be sometimes annoying, but it's the least irksome one... so far. I've been eyeing Rust and Zig, and they sound nice (but every one of dem motherfuckers look nice before you start fiddling with 'em) yet ten years from now, if I'm still kicking the caret, I will be feeding some data into a clj repl, I'm tellin' ya. That shit just fucking works and makes sense to me. I don't know how making it stop making sense, it just fucking does.
I just want a way of doing immutability until production and let a compiler figure out how to optimize that into potentially mutable efficient code since it can on those guarantees.
Clojure's persistent data structures are extremely fast and memory efficient. Yes, it's technically not a complete zero-overhead, pragmatically speaking - the overhead is extremely tiny. Performance usually is not a bottleneck - typically you're I/O bound, algorithm-bound, not immutability-bound. When it truly matters, you can always drop to mutable host language structures - Clojure is a "hosted" language, it sits atop your language stack - JVM/JS/Dart, then it all depends on the runtime - when in javaland, JVM optimizations feel like blackmagicfuckery - there's JIT, escape analysis (it proves objects don't escape and stack-allocates them), dead code elimination, etc. For like 95% of use cases using immutable-first language (in this example Clojure) for perf, is absolutely almost never a problem.
Haskell is even more faster because it's pure by default, compiler optimizes aggressively.
Elixir is a bit of a different story - it might be slower than Clojure for CPU-bound work, but only because BEAM focuses on consistent (not peak) performance.
Pragmatically, for the tasks that are CPU-bound and the requirement is "absolute zero-cost immutability" - Rust is a great choice today. However, the trade off is that development cycle is dramatically slower in Rust, that compared to Clojure. REPL-driven nature of Clojure allows you to prototype and build very fast.
From many different utilitarian points, Clojure is enormously practical language, I highly recommend getting some familiarity with it, even if it feels very niche today. I think it was Stu Halloway who said something like: "when Python was the same age of Clojure, it was also a niche language"
This doesn’t make much sense. One of the benefits of immutability is that once you create a data structure, it doesn’t change and you can treat it as a value (pass it around, share it between threads without cloning it, etc.). If you now allow modifications, you’re suddenly violating all those guarantees and you need to write code that defensively makes clones, so you’re right back where you started. In Clojure, you can cheat at points with transients where the programmer knows that a certain data structure is only seen by a single thread of execution, but you’re still immutable most of the time.
Depends on your target. Clojure targets the JVM by default and that has very different constraints than say, compiling to JavaScript for the browser or node.
Compiling to a JS engine this would be great because immutability has a runtime cost
Runtime cost of using Clojurescipt is undeniably there but for most applications is pretty negligible price to pay for the big wins. In practice, Clojurescript apps can often perform faster than similar apps built traditionally - especially for things like render optimization - immutable data enables cheap equality checks for memoization, it prevents unnecessary re-renders; data transform pipelines - transducers give you lazy evaluation, it's great for filtering/mapping through large datasets; caching - immutable data is safe to cache indefinitely, you don't have to worry about stale data;
You guys keep worrying about some theoretical "costs" - in practice, I have yet to encounter a problem that genuinely makes it so impossibly slow that Clojuresript just outright can't be used. Situations where it incurs a practical cost to pay are outliers, not a general rule.
Not all, and it is always preferable for it not to have a cost.
> I have yet to encounter a problem that genuinely makes it so impossibly slow that Clojuresript just outright can't be used
There’s a big swath of work that could benefit from the development streamlining that something like clojurescript or similar projects can give but any performance hit is deadly, like e-commerce.
There is also the fact that it doesn’t have 100% bindings to the raw JS and DOM APIs if I recall correctly, it’s often wrapped around React or assumed to be
Of course. That's why every programmer today is fluent in assembly.
> like e-commerce.
You're misinformed. I don't know where you're getting all this, but I have done enough front-end work and have built ecommerce solutions - clojurescript works better than many different things I've used, and believe me - I've tried more than just a few things over the years - livescript, gorillascript, coffeescript, icedcoffescript, typescript, haste, fay, ghcjs; I've considered elm, purescript and reasonml. The only thing I have not built with it for web is games. That's the only domain where theoretically I may have hit limitations, but because I've never done that in practice, I can't even say what those limitations could be, but I know, people have done that with great success.
Pitch.com have built their platform for presentations in clojurescript, Whimsical - their chart drawing boards, and you don't even have to imagine - that shit would need to squeeze out every drop of a cycle for canvas/WebGL and DOM updates. Most web app bottlenecks are architectural - bad algorithms, inefficient data structures, unnecessary re-renders, and Clojurescript is just amazing to deal with these kinds of problems.
> bindings to the raw JS and DOM APIs
You're saying nonsense. Clojurescript directly can call any javascript function and whatever APIs. Please at least google, or ask an LLM before blurting out nonsense like this. I don't know what emotional level of insecurities you're dealing with, but I advise you to try out things instead of prematurely reaching the level of "I hate this" without even understanding what you're actually hating. It's not that hard. These days you don't even have to learn all the intricacies of compiling it, you can use Squint - the light-weight dialect of Clojurescript. It's as easy as using a regular script tag.
Or don't use it, who cares? Stay in your mental FUD castle, letting theoretical constraints become real ones by never testing their boundaries. I have used Clojurescript, I liked it and will use it again - I have seen with my own eyes how it actually works much better than any other alternatives I have tried so far - in practical web apps that I shipped to production. I'm not married to it - it simply makes sense. For many practical reasons it does. Whenever it stops making sense and I find a better alternative, I will switch without hesitation. For now, it just works for me.
> Also, experiencing immutability benefits in a mutable-first language can feel like 'meh'.
I felt that way in the latest versions of Scheme, even. It’s bolted on. In contrast, in Clojure, it’s extremely fundamental and baked in from the start.
exactly, react could not deal with mutable object so they decided to make immutability seem to be something that if you did not use before you did not understood programming.
React made immutability patterns more relevant which increased discussion of it. Some people did get preachy about it. Yet dismissing immutability entirely just because of that misses the entire point of why it's actually useful in managing complex state.
Have you ever thought about instead of having emotional reaction to obnoxious gatekeeping to learn about actual benefits of immutability?
Thank you, will keep an eye on it. Auth0 is definitely the closest I've seen to what my business needs (and I've spent waaay to much time one trials and demos of too many products so far).
If it would:
a.) Perform group assignment based on SAML attributes (like Okta's group rules), and,
b.) "natively" support SAML Federations used in the Higher Education space (which Shibboleth appears to be the only thing that supports)
I'd sign up tomorrow and start migration of my 150k users.
You can still simulate the old ways without electrical circuits. Just put one of these seemingly primordial devices on your stove and adjust the heat and time to your likening.