back

by iLemming·9mo ago·view on hn ↗
Javascript DOES NOT in fact have built-in immutability similar to Clojure's immutable structures - those are shallow, runtime-enforced restrictions, while Clojure immutable structures provide deep, structural immutability. They are based on structural sharing and are very memory/performance efficient.

Default immutability in Clojure is pretty big deal idea. Rich Hickey spent around two years designing the language around them. They are not superficial runtime restrictions but are an essential part of the language's data model.

2 comments
I didn't say that it does have exhaustive immutability support. I said the value of it is known. They wouldn't have added the (limited) support that they did if they didn't understand this. The community wouldn't have built innumerable tools for immutability if they didn't understand the benefits. And in any case, you can't just shove a whole different model of handling objects into a thirty year old language that didn't see any truly structural changes until ten years ago.
> I didn't say that it does have exhaustive immutability support

seal and freeze in js are not 'immutability'. You said what you said - "JavaScript itself has built in immutability features (seal, freeze)".

I corrected you, don't feel bad about it. It's totally fine to not to know some things and it's completely normal to be wrong on occasion. We are all here to learn, not to argue who's toy truck is better. Learning means going from state of not knowing to the state of TIL.

> you can't just shove a whole different model of handling objects into a thirty year old language

Clojurescript did. Like 14-15 years ago or so. And it's not so dramatically difficult to use. Far more simpler than Javascript, in fact.

Your toy truck is being overly pedantic
I am not being pedantic, there's critical fundamental conceptual difference that has real implications for how people write and reason about code.

There's performance reasoning, different level of guarantees, and entirely different programming model.

When someone hears "JS has built-in immutability features", they might think, "great, why do I even need to look at Haskell, Elixir, Clojure, if I have all the FP features I need right here?". Conflating these concepts helps no one - it's like saying: "wearing a raincoat means you're waterproof". Okay, you're technically not 100% wrong, but it's so misleading that it becomes effectively wrong for anyone trying to understand the actual concept.

Sure, though Immutability.js did have persistent data structures like Clojure.
yeah, immutability.js is a solid engineering effort to retrofit immutability onto a mutable-first language. It works, but: it's never as ergonomic as language-native immutability and it just feels like you're swimming upstream against JS defaults. It's nowhere near Clojure's elegance. Clojure ecosystem assumes immutability everywhere and has more mature patterns built around it.

In Clojure, it just feels natural. In js - it feels like extra work. But for sure, if I'm not allowed to write in Clojurescript, immutability.js is a good compromise.

I meant to point out that of course there is value in immutability beyond shared datastructures.

I tried Immutability.js back in the day and hated it like any bolted-on solution.

Especially before Typescript, what happened is that you'd accidentally assign foo.bar = 42 when you should have set foo.set('bar', 42) and cause annoying bugs since it didn't update anything. You could never just use normal JS operations.

Really more trouble than it was worth.

And my issue with Clojure after using it five years is the immense amount of work it took to understand code without static typing. I remember following code with pencil and paper to figure out wtf was happening. And doing a bunch of research to see if it was intentional that, e.g. a user map might not have a :username key/val. Like does that represent a user in a certain state or is that a bug? Rinse and repeat.

> immense amount of work it took to understand code without static typing.

I've used it almost a decade - only felt that way briefly at the start. Idiomatic Clojure data passing is straightforward once you internalize the patterns. Data is transparent - a map is just a map - you can inspect it instantly, in place - no hidden state, no wrapping it in objects. When need some rigidity - Spec/Malli are great. A missing key in a map is such a rare problem for me, honestly, I think it's a design problem, you cannot blame dynamically-typed lang for it, and Clojure is dynamic for many good reasons. The language by default doesn't enforce rigor, so you must impose it yourself, and when you don't, you may get confused, but that's not the language flaw - it's the trade-off of dynamic typing. On the other hand, when I want to express something like "function must accept only prime numbers", I can't even do that in statically typed language without plucking my eyebrow. Static typing solves some problems but creates others. Dynamic typing eschews compile-time guarantees but grants you enormous runtime flexibility - trade-offs.