Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I don't think the benefits of immutability haven't been discovered in js. Immutable.js has existed for over a decade, and JavaScript itself has built in immutability features (seal, freeze). This is an effort to make vanilla Typescript have default immutable properties at compile time.


It doesn't make sense to say that. Other languages had it from the start, and it has been a success. Immutable.js is 10% as good as built-in immutability and 90% as painful. Seal/freeze,readonly, are tiny local fixes that again are good, but nothing like "default" immutability.

It's too late and you can't dismiss it as "been tried and didn't get traction".


That's not what I said, and that's not what my reply is about. The value of immutability is known. That's the point of this post. The author isn't a TC39 member (or at least I don't think they are). They're doing what they can with the tools they have.


You didn't understand what you were replying to. Immutability cannot be discovered later on in that sense (in practice).


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.


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.


one thing that it's missing in JS to fully harness the benefits of immutability is some kind of equality semantics where two identical objects are treated the same


They were going to do this with Records and Tuples but that got scrapped for reasons I’m not entirely clear on.

It appears a small proposal along these lines has appeared in then wake of that called Composites[0]. It’s a less ambitious version certainly.

[0]: https://github.com/tc39/proposal-composites


Records and Tuples were scrapped, but as this is JavaScript, there is a user-land implementation available here: https://github.com/seanmorris/libtuple


Userland implementations are never as performant as native implementations. That's the whole point of trying to add immutability to the standard.


even when performance might not be an issue or an objective, there are other concerns about an user land implementation: lack of syntax is a bummer, and lack of support in the ecosystem is the other giant one - for example, can I use this as props for a React component?


yes, I'm aware of composites (and of the sad fate of Records and Tuples) and I'm hopeful they will improve things. One thing that I'm not getting from the spec is the behavior of the equality semantics in case a Date (or a Temporal object) is part of the object.

In other words, what is the result of Composite.equal(Composite({a: new Date(2025, 10, 19)}, Composite({a: new Date(2025, 10, 19)})? What is the result of Composite.equal(Composite({a: Temporal.PlainDate(2025, 10, 19)}, Composite({a: PlainDate(2025, 10, 19)})?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: