I don’t spend thousands on computer hardware so that lazy devs can get lazier.
Functional programming is great. What’s not great is loading the entire closure VM environment into my browser - resulting in the software running (in this case) 50x slower. FP is no excuse for making my computer crawl to a halt.
And there’s no essential reason FP needs to be slow. For example, look at how well llvm optimizes map/filter/fold in rust. In many cases they’re faster than their imperative counterparts! There are other ways to benefit from immutability that don’t involve burying a garbage collector in useless work. For example, React is a lovely example of immutable ideas, and a fast runtime.
I spent a few thousand dollars on a new Mac laptop recently. I wonder what percentage of my clock cycles are going to be wasted due to bad abstractions and inefficient code? Probably most of them. I wish I could take the money I spent on the machine and instead pay people to improve their software. I don’t have billions of cycles per second of actual work to do.
There's no VM in clojurescript, it compiles to JS, it is tree-shaken and heavily optimized and minified through Google's Closure compiler.
> resulting in the software running (in this case) 50x slower
The speedup is not a result of abandoning clojurescript, it's from moving from immutable data structures to mutable arrays and primitives. The same can be done in clojurescript or javascript.
I think this is a common misunderstanding, that's why I'm reacting. Nobody claims immutable data structures to be the silver bullet. Computation-heavy parts need to be done in low level code and with primitive types.
More or less, yes.
The majority of the perf increase here came from two things: 1. going from immutable->mutable, 2. going from CLJS/JS->Rust in the perf critical part. Doing just 1. would likely improve the performance, but not as much as doing both 1. and 2.
Doing just 1. while staying with ClojureScript could potentially be accomplished with transients [0] at the cost of making a major chunk of the code non-idiomatic Clojure. I actually played with transients here before attempting the rewrite, but haven't got too promising results though.
Proper abstractions aid in understanding and can ideally be optimized away. Poor abstractions hinder it and slow things down.
I believe it's possible to understand the code you create, even in the presence of mutation (though you can no longer store old values for free, and need to use cloning or other approaches). You need to restrict which code is responsible for mutating state (using careful program architecture), and restrict the ability to mutate data while other pointers to the data exist (Rust imposes these restrictions). Interestingly, the Relm architecture is a translation of the Elm architecture (Elm is an immutable language) to Rust code (Rust is a mutable language) which restricts which code is responsible for mutating state, and Rust restricts the ability to mutate data while other pointers to the data exist.
Interestingly, Rust unifies immutable and mutable data structures. The im library (https://docs.rs/im) uses the same tree-based immutable data structures as Clojure and such, but exposes an API closer to Rust's stdlib containers (including mutation). However im's performance characteristics are different from Rust's stdlib; clones are shallow and take O(1) time, while IndexMut is slower and copies tree nodes whenever that node's refcount is greater than 1. immer.js (https://github.com/immerjs/immer) has a somewhat similar API, but a different implementation (I think it uses standard JS arrays and copies the whole thing when you mutate one element).
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.
Though I must admit, every time my browser lags when viewing what SHOULD be a static site, I do die a little inside.
We all know that performance takes extra work to ensure, then, and is uncertain even with the extra work.
"Lazy devs", Work on a team in C graphic code and watch nothing get done.
It doesn't matter what language they move on to. Rust and C++ are both good.