Hacker News new | ask | show | jobs
by saosebastiao 3177 days ago
> I don't understand this. Clojurescript's "runtime" itself most compiles away in Closure advanced optimizations stage (in fact a compiled Hello World Clojurescript app is only 1 line of JS -- no added runtime at all). I don't understand what about the Clojurescript runtime process should be "huge" and "slow." This contrasts with other languages like Elm that do indeed embed a large runtime with the program, but Clojurescript does not do this.

Clojurescript now does a good job with Closure's advanced optimizations, but it has upper limits to how well it can do. For a full sized app, you can expect clojurescript's runtime code to bloat to 100k to 150k...which isn't the end of the world, but it certainly isn't good either.

While clojurescript and javascript are both dynamically typed, their type systems are semantically different. In order to approximate the semantics of the clojure type system, clojurescript has to build its own dynamic type checking system into a system that is already dynamically type checked. FWIR, the reason that clojure.spec was built into the standard distribution of clojurescript (whereas it is an optional library in clojure) was so that the compiler could perform type erasure on code with type hints...something done by default in static languages like bucklescript, scalajs, and typescript.

So while clojurescript does a good job with dead code elimination specifically, thanks to the closure optimizer, it is still a language that is inherently hard for compilers to otherwise optimize.

> 2) I am genuinely curious what performance problems you had. I'm working on a very large Clojurescript app that processes dozens of real-time incoming data points every second over a websocket and performs real-time analytics and graphical display. If ever there was a test for performance, this would be it. Aside from the rare and simple bottleneck that needed some extra thought (maybe 2 or 3 such moments in 3 years of development on the project), there have been nearly no obstacles relating to runtime speed for the app. The 2 or 3 bottlenecks I mention had minor solutions and would have occurred in any language, and were very easy to resolve.

The internet is full of examples of clojure programmers asking how to optimize code up to the already pitiful levels of performance that you can get out of javascript. Every language has it to some degree, but for some reason, it was always a 10x-100x difference for me. Collections in particular were always really bad for me. And the suggestions I received from more experienced clojurists always ended up pushing me away from what I considered to be idiomatic in clojure. Use defrecord instead of hashmaps, use javascript arrays or vectors instead of seqs, use goog.stringbuffer instead of str, use type hints whenever possible, etc.. Fast clojurescript and "idiomatic" (whatever that is supposed to mean in a lisp) clojure were far enough apart that it might as well have been scheme vs clojure.

> And Clojurescript's fast, immutable data structures have inspired major libraries and even other languages entirely. They are battle-tested and performant.

Clojurescript's immutable data structures are indeed pretty fast for immutable data structures run on a javascript runtime. But they are hardly fast. In fact, here[0] is an example of what I was talking about before: cljs written in an idiomatically clj style that performed terribly when used in cljs. And the answer on how to speed it up was to make it more like javascript!

I'm well aware of the rounds of praise that Om got when they showed how using cljs' native immutable data structures sped up React code over that written in javascript. I'd be careful to extrapolate too far with that. That optimization happened to involve a niche benefit of immutable structures (equality checking can use O(1) reference equality instead of O(n) structural equality) addressing a niche bottleneck in React (equality checking in the virtual dom). Overall, immutable datastructures tend to be about the same speed on most operations, but drastically slower on some operations, and drastically more memory hungry to boot. On servers with knowable processing power and knowably large quantities of jvm memory, that's often a tradeoff worth making for the semantic benefits of immutability. On some random user's computer using whatever javascript VM that they likely chose without consideration for how I would use it, I always felt bad making that tradeoff.

[0] https://stackoverflow.com/questions/21721028/how-to-improve-...