5 ms·
It’s interesting to watch other languages discover the benefits of immutability. Once you’ve worked in an environment where it’s the norm, it’s difficult to mov
by drob518 1y ago
It’s interesting to watch other languages discover the benefits of immutability. Once you’ve worked in an environment where it’s the norm, it’s difficult to move back. I’d note that Clojure delivered default immutability in 2009 and it’s one of the keys to its programming model.
- hden 1y agoMutability is overrated.
- recursive 1y agoImmutability 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.
- WolfOliver 1y agoexactly, 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.
- iLemming 1y agoReact 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?
- iLemming 1y agoImmutability 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.
- drob518 1y ago> 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.
- no_wizard 1y agoI 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. No runtime cost in production is the goal
- iLemming 1y ago> No runtime cost in production is the goal 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"
- 1y ago
- drob518 1y agoThe 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. [1] https://clojure.org/reference/transients https://clojure.org/reference/transients
- bastawhiz 1y agoI 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.
- iLemming 1y agoJavascript 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.
- hombre_fatal 1y agoSure, though Immutability.js did have persistent data structures like Clojure.
- iLemming 1y agoyeah, 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.
- hombre_fatal 1y agoI 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.
- iLemming 1y agoAlso, interestingly Clojurescript compiler in many cases emits safer js code despite being dynamically typed. Typescript removes all the type info from emmitted js, while Clojure retains strong typing guarantees in compiled code.
- marcelr 1y agoprogramming with immutability has been best practices in js/ts for almost a decade however, enforcing it is somewhat difficult & there are still quite a bit lacking with working with plain objects or maps/sets.
- gspencley 1y agoWe shouldn't forget that there are trade-offs, however. And it depends on the language's runtime in question. As we all know, TypeScript is a super-set of JavaScript so at the end of the day your code is running in V8, JSCore or SpiderMonkey - depending on what browser the end user is using, as an interpreted language. It is also a loosely typed language with zero concept of immutability at the native runtime level. And immutability in JavaScript, without native support that we could hopefully see in some hypothetical future version of EcmaScript, has the potential to impact runtime performance. I work for a SaaS company that makes a B2B web application that has over 4 million lines of TypeScript code. It shouldn't surprise anyone to learn that we are pushing the browser to its limits and are learning a lot about scalability. One of my team-mates is a performance engineer who has code checked into Chrome and will often show us what our JavaScript code is doing in the V8 source code. One expensive operation in JavaScript is cloning objects, which includes arrays in JavaScript. If you do that a lot.. if, say, you're using something like Redux or ngrx where immutability is a design goal and so you're cloning your application's runtime state object with each and every single state change, you are extremely de-optimized for performance depending on how much state you are holding onto. And, for better or worse, there is a push towards making web applications as stateful as native desktop applications. Gone are the days where your servers can own your state and your clients just be "dumb" presentation and views. Businesses want full "offline mode." The relationship is shifting to one where your backends are becoming leaner .. in some cases being reduced to storage engines, while the bulk of your application's implementation happens in the client. Not because we engineers want to, but because the business goal necessitates it. Then consider the spread operator, and how much you might see it in TypeScript code: const foo = { ...bar, // clones bar, so your N-value of this simple expression is pegged to how large this object is newPropertyValue, }; // same thing, clones original array in order to push a single item, because "immutability is good, because I was told it is" const foo = [...array, newItem]; And then consider all of the "immutable" Array functions like .reduce(), .map(), .filter() They're nice, syntactically ... I love them from a code maintenance and readability point of view. But I'm coming across "intermediate" web developers who don't know how to write a classic for-loop and will make an O(N) operation into an O(N^3) because they're chaining these together with no consideration for the performance impact. And of course you can write performant code or non-performant code in any language. And I am the first to preach that you should write clean, easy to maintain code and then profile to discover your bottlenecks and optimize accordingly. But that doesn't change the fact that JavaScript has no native immutability and the way to write immutable JavaScript will put you in a position where performance is going to be worse overall because the tools you are forced to reach for, as matter of course, are themselves inherently de-optimized.
- Random09 1y agoIt's redundant in single thread environment. Everyone moved to mobile while pages are getting slower and slower, using more and more memory. This is not the way. Immutability has its uses, but it's not good for most web pages.
- iLemming 1y agoYou're just waving off the whole bag of benefits: Yes, js runs in a single-threaded environment for user code, but immutability still provides an immense value: predictability, simpler debugging, time-travel debugging, react/framework optimizations. Modern js engines are optimized for short-lived objects, and creating new objects instead of mutating uses more memory only temporarily. Performance impact of immutability is so absolutely negligible compared to so many other factors (large bundles, unoptimized images, excessive DOM manipulation) You're blaming the wrong thing for overblown memory. I don't know a single website that is bloated and slow only because the makers decided to use immutable datastructures. In fact, you might be exactly incorrect - maybe web pages getting slower and slower because we're now trying to have more logic in them, building more sophisticated programs into them, and the problem is exactly that - we are reaching the point that is no longer simple to reason about them? Reasoning about the code in an immutable-first PL is so much simpler, you probably have no idea, otherwise you wouldn't be saying "this is not the way"
- pjmlp 1y agoIf we are pointing dates, ML did it in 1973, or if you prefer the first mature implementation SML, in 1983. The Purely Functional Data Structures book, that Clojure data structures are based on, is from 1996. This is how far back we're behind the times.
- drob518 1y agoCool. I didn’t realize ML had such a focus on immutability as well. I have never done any serious work in ML and it’s a hole in my knowledge. I have to go back and do a project of some sort using it (and probably one in Ocaml as well). What data structures does ML use under the hood to keep things efficient? Clojure uses Bagwell’s Hashed Array-Mapped Tries (HAMT), but Bagwell only wrote the first papers on that in about 2000. Okasaki’s book came out in 1998, and much of the work around persistent data structures was done in the late 1980s and 1990s. But ML predates most of that, right?