20 ms·
The immutable hype is finally fading. People starting to realize the drawbacks of treating hardware as an infinite resource.
by lxe 5y ago
The immutable hype is finally fading. People starting to realize the drawbacks of treating hardware as an infinite resource.
- azakai 5y agoThis article doesn't really support that. ClosureScript targets JavaScript, which is a platform that doesn't have special support for optimizing immutability.
- notacoward 5y agoHow would one optimize for immutability in this case, other than turning it back into mutability behind the scenes? I've certainly seem some code written in an "immutable" style where it was pretty clear that the intent was for one data structure to be a mutation of another, just called something else because the language required it. That case might be easy to optimize ... but the general case?
- azakai 5y agoI'm not an expert on this, but one example is that immutability lets you operate safely on things in parallel. But JS VMs are not aware of objects that are immutable in Clojure's semantics, and in any case, do not operate on objects in parallel anyhow.
- memco 5y ago> How would one optimize for immutability in this case, other than turning it back into mutability behind the scenes? Roc-lang, which is a functional, systems language in development uses something called opportunistic in-place mutation to do just that. Here's a video where the creator talks about it: https://youtu.be/vzfy4EKwG_Y?t=1276 https://youtu.be/vzfy4EKwG_Y?t=1276
- kevin_thibedeau 5y agoPretty bog standard behavior for a compiler backend translating immutables in IR. Including a runtime compiler into app code is the next stage in the evolution of cycle burning leetness.
- fulafel 5y agoGenerally in compiler technology, immutability is an important tool in letting compilers reason about and make program transformations. See eg the "single static assignment" intermediate-representation form that is mainstream in low level language compilers. But SSA form isn't as good as having the original program expressed immutably, because you get false or incidental data dependencies if the compiler has to conservatively derive the optimization-friendly SSA representation out of the original non-immutable code. In practice a JS implementation that had special optimizations for code using immutability as a convention might for example auto-parallelize code. Also it by no means a bad thing if a compiler turns a piece of easy to reason about functional code "back" to generated code that exploits local mutability behind the scenes in some circumstances, that's exactly how we want it to work. We still get the robustness guarantees of semantics where our objects don't change from under us in programmer visible ways.
- gpderetta 5y agoTalking about parallelization opportunities is a bit pointless when you need 50 cores to match the performance of the single threaded code (in the best case, assuming perfect scaling).
- azakai 5y agoFair enough, but parallelism isn't just about cores since SIMD can also help. Also, immutability doesn't just help through parallelism, it also allows other things (as another example, avoiding redundant work like loads of an immutable field and computations on them). Would that help with a huge 50x difference? Maybe not, but the point is that evaluating the benefits of immutability on a VM that does not optimize it - JS VMs - is not relevant. (And that 50x might also be caused by other limitations of JS VMs and not immutability at all, like say deopts.)
- fulafel 5y agoI disagree - lots of compiler work is done on languages that aren't best in class for high performance work. Look at all the effort that people are putting into making Python faster. And indeed JS itself, it wasn't always this fast. High level language users live by "There's more to life than increasing its speed" and then if they take off, people come work on performance and make them faster. Also let's not forget that this was already "fast enough" for a long time before the 50x rewrite.
- rektide 5y agomutability is a data structuring virtualization but i'd just as much suspect the runtime virtualization. that the bundle used to be 570kB isnt an immutability issue. itcs that clojurescript drags in a whole clojure runtime, a new virtualization layer atop the js runtime. that, to me, is the most likely suspect. that said, for sure, short tbeow away high gc allocation patterns are generally not good. at work there's a lot of "functional" patterns, nary a for loop in sight. this endless .map() .filter() usage causes near exactly similar issues, with shortived objects. it seems ultra sad & silly to me. waste after waste. but i also think we have much more deeply rooted problems.
- jdlshore 5y agoAre you sure about the short-lived allocations being a problem for the collector? My understanding of modern generational garbage collectors was that they performed quite well with short-lived garbage. Not as well as not creating the garbage in the first place, of course, but not so badly as to be a problem in most cases.
- ncmncm 5y ago"Perform quite well" is always relative to some reference. The oldest trick in the book is comparing to something even slower and saying "see? fast!". GC apologists seek to normalize this behavior. They often succeed, at that. Performing quite well against actually fast things, less often.
- jdlshore 5y agoYou seem to have an axe to grind. Performance isn’t black and white. Optimizing your memory usage isn’t going to do you a whit of good if you’re constrained by your database queries. Optimizing your DB queries isn’t going to do you any good if you’re constrained by a chatty microservice architecture. Optimizing your UI response time isn’t going to do you any good if you’re already below the threshold of perceived speed. Etc. GC performance on short-lived objects is quite good in enough situations to matter, such that optimizing for it, rather than your application architecture, is likely foolish outside of performance sensitive loops. Time is always limited. Spending your optimization budget on micro-optimizations is short-sighted.
- deleted 5y ago[deleted]
- notacoward 5y agoThis part... > for the high frame-rate, heavy animations this puts a lot of pressure on CPU and memory ...does seem to suggest that the "garbage multiplier" effect of immutability is an ill fit for applications that also create a lot of garbage naturally. Note that this is about as close to an apples-to-apples comparison as we're likely to get - the same application implemented two different ways - so it's not the application's innate object-lifetime characteristics that are the problem. That's an implementation artifact. The question is: how many applications are likely to hit this same limit? Is this a rare case, or is it common? If it's common, it is indeed an indictment of the "immutable" approach. Otherwise, not so much.
- xyzzy123 5y agoI've always thought of immutability as great for situations where you want to "explore" (clone complex current state and go do some "what if"), need internal transactions, or allow time travel (snapshot/undo/redo) - situations where the state sharing is both efficient and feels "natural". Also if the data/history are relatively small compared to the available memory it's a fine default that generally leads to "nicer" code. Video doesn't seem at first glance like such a great fit.
- kccqzy 5y agoVideo can be played backwards and forwards, can be sought, or jumped to a particular point in time. It fits well with the "time travel" benefit of immutable data structure. The author mentioned it was extremely easy to implement some kind of a checkpoint or key framing with immutability. That's exactly using immutability to its strength.
- titzer 5y agoThe downside of immutability is the sheer volume of data (in the form of pixels) that needs to be pushed around. A single 4k frame is 8.3 million pixels, so you are looking at over 30MiB of data for 32-bit color, and you gotta push 30, maybe 60 of those a second. Maybe if you have a really good garbage collector (or a custom one, because frames are all the same size) you can get away with allocating that much data and freeing it every second. But that doesn't free you from the fact that you are not utilizing hardware caches well; you don't get good spatial locality at the hardware level unless you reuse the same physical pages of memory for every frame. And you can basically only do that if you have a mutable design.
- slmjkdbtl 5y agoI fantasize about a future where we have enough CPU and memory that we can waste them on nice stuff like immutable data structures and software rendering.
- josephg 5y agoI fantasize about a future in which buying a faster computer means my software runs faster. I don’t spend thousands on computer hardware so that lazy devs can get lazier.
- slmjkdbtl 5y agoI wouldn't characterize hoping to use immutable data structures and software rendering as trying to be lazy
- ncmncm 5y agoYet, we may characterize lazy programmers as hoping to use immutable data structures and pay no attention to performance. We all know that performance takes extra work to ensure, then, and is uncertain even with the extra work.
- drenvuk 5y agoI would. Instead of properly managing mutable state (which can be difficult in situations with growing teams and complex application logic) people are opting to just copy everything or copy a subset of the tree they need so they don't have to think about it. Immutability is bad for performance when the purpose is not recalculating a certain state after a certain number of operations(memoization). Many of the best practices that have cropped up in the past few years has been more for helping teams of people deal with growing code bases rather than helping programmers deal with limited hardware. In computer science this should be self explanatory. For optimal runtimes the act of making copies is avoided. Why people usually seem to ignore the fact that they're wasting cycles for the sake of the holy grail of clean, functional programming and immutability has eluded me. Typescript, focus on immutability, microservices even. I hate all of them but they have their purposes. They solve people problems. Maximizing hardware performance is not in the list though.
- bachmeier 5y agoThis is an application where the goal is to squeeze every last drop of performance possible out of the processor. The "every last drop of performance" crowd has never been the source of the "immutability hype". Your comment is dismissive of many domains of programming - immutable didn't become a thing because others weren't as enlightened as you.
- deleted 5y ago[deleted]
- jcelerier 5y ago> This is an application where the goal is to squeeze every last drop of performance possible out of the processor. I have a hard time thinking of an application for which this isn't the case. If my cooking recipe app / website is too slow and/or eats too much battery (and god fucking knows they are) I'll look for a competitor immediately.
- detaro 5y agonot being too slow and "squeeze every last drop of performance possible" is not really the same, and the latter is an expensive tradeoff to make.
- bsg75 5y agoWhat is the connection between mutability and excessive hardware usage?
- cjcampbell 5y agoAs an oversimplified example, in using an immutable screen buffer, a change between frames results in allocation of a full buffer rather than overwriting memory within the buffer (though one could probably think of ways to optimize this for the use case). Excess comes either in the form of unnecessary (relative to mutable) memory usage and/or CPU cycles necessary to support high-levels of garbage collection.
- peoplefromibiza 5y agothat's only because js is "stupid" if you have the string "hello" and somewhere else "hello world" you can retain only one copy of "hello" because it's guaranteed it won't change. but js vm it's not smart enough for that.
- __s 5y agoYou're wrong, JS has immutable strings & so VMs use ropes to make mutable usage & slicing fast https://gist.github.com/mraleph/3397008 https://gist.github.com/mraleph/3397008 https://twitter.com/rauschma/status/1269964154275799041 https://twitter.com/rauschma/status/1269964154275799041
- peoplefromibiza 5y agothanks my bad, I learned something new. anyway this proves that immutable data structures are not inherently slow, this is infact an optimization that makes things faster.
- knubie 5y ago> in using an immutable screen buffer, a change between frames results in allocation of a full buffer rather than overwriting memory within the buffer That’s actually not how clojure’s immutable data structures work. They use structural sharing, so only the portion that changes (roughly) needs new memory allocated, and only the parts that changed get garbage collected, so it is a bit more efficient than that.
- rtpg 5y agoWhat a boring takeaway from this. Beyond the fact that the immutable data structures proposed by Clojure/script tend to perform very well in a lot of "normal" cases (and in a lot of normal web-app workflows your stuff is immutable, like "query then display the result from an API"), at least to me it feels like asciinema is a very good example of a case where you have tougher-than-average performance requirements. Not to say that we shouldn't have "everything be performant" but drawing a bunch of stuff to screens is _the classic_ performance question. Whereas most "business apps" people here work on to a day-to-day have different performance issues. Rewriting your CRUD frontend in Rust isn't going to make your DB queries faster
- hedora 5y ago> Rewriting your CRUD frontend in Rust isn't going to make your DB queries faster A typical consumer disk can do 1,000,000 IOPS (enterprise is one generation behind, and slower at the moment), with millisecond read and write latencies. Are there any managed CRUD frontend languages that are fast enough to keep up with that? (By “keep up”, I mean “be less than half the hardware I provision at scale”)
- ncmncm 5y agoWon't make them slower, anyway. There are often performance bottlenecks you didn't know about, and had blamed on database (or whatever) interaction overhead. It will never feel worthwhile to dig into each candidate, because any payback seems too unlikely. Not having left scope for such bottlenecks means you can be confident they are not there. Re-implementing once is a lot less work than diving into each possible bottleneck. Improving your actual database operations, after, is more likely to have an effect when some other bottleneck doesn't mask the improvement. You don't have to do it in Rust. Any optimization you could do in Rust is probably easier in C++, and also easier to find maintainers for.
- Ar-Curunir 5y ago> Any optimization you could do in Rust is probably easier in C++, and also easier to find maintainers for. At least the first part is not necessarily true. E.g., in C++, you might make defensive copies, whereas in Rust the lifetime system will track things for you.
- niels_bom 5y agoThis talk by Richard Feldman about Roc (a new language) goed into why immutable does not necessarily mean slow and given enough attention can mean higher performance in certain cases: https://youtu.be/vzfy4EKwG_Y https://youtu.be/vzfy4EKwG_Y
- peoplefromibiza 5y agoor maybe is JavaScript hype and the make concurrent programming impossible that it's finally dying. Immutability is alive and well, it's simply a matter of js runtime not supporting it, because the developers thought "one thread ought be enough for anybody".
- mping 5y agoWell the immutability hype allowed the author to build the previous incantions of the library. At this point, I hoped everyone understood the tradeoffs of using abstractions. Otherwise we should all be programming on assembly.
- zupa-hu 5y agoThis. If the project was reimplemented in assembly, it would be faster and smaller and the same conclusion could be drawn: “finally the high level programming hype is over”. come on..
- legulere 5y agoThe benefits of immutability are still there though. You should generally design immutable by default and use mutability for performance where it matters. Rust which was used here also has immutability by default and mutability is an explicit opt-in.