Hacker News new | ask | show | jobs
by kllrnohj 2496 days ago
The response to "but is it slow" is pretty disappointingly bad.

> No. Clojure is not slow. Oh, look, it’s not C. It’s not assembler. If nanoseconds are your concern than you probably don’t want Clojure in your innermost loops. You also probably don’t want Java, or C#. But 99.9% of the software we write nowadays has no need of nanosecond performance. I’ve built a real time, GUI based, animated space war game using Clojure. I could keep the frame rates up in the high 20s even with hundreds of objects on the screen. Clojure is not slow.

If you're going to respond to this question at least provide some comparison maybe.

But otherwise that anecdote of "I could keep the frame rates up in the high 20s even with hundreds of objects on the screen." absolutely screams extremely slow. High 20s FPS with hundreds of objects is incredibly bad on the surface of things. Maybe it's closures fault, maybe it isn't and is instead the fault of whatever was doing the drawing. But it's not a good look either way if that's the only data point that can be provided.

Similarly the IDE/dynamic type question seems to have missed the main downside of dynamic languages - lack of good IDE & other tooling support. How well are things auto-completed for me? How well does the IDE warn I've made a type error before I've gone through a long compile & test iteration loop? How well do linters or other things work, or is there some aspect of LISP that means this is just not an issue like it is in other languages?

4 comments

The biggest thing keeping me from ever seriously learning Clojure is the JVM. Slow startup time means I'd never use Clojure for "scripts", and I certainly don't want to have to manage the JVM in production scenarios, so when would I use Clojure? If there was a native version that could produce static binaries like Go/Nim/Rust I'd be much more interested to learn it.
I found managing production JVM is amazing. In fact, little other runtimes come close in my opinion. What don't you like about it?

For scripting, there's a lot of ways to script efficiently with Clojure, it's actually great for it as well. So, for most my scripts, I don't really mind waiting 1 second for them to start. That said, if you wanted them to start faster, using ClojureScript takes you under 100ms. And using Joker (https://github.com/candid82/joker) takes you under 50ms.

When I need even faster startup for scripts and also need performant runtime, I've been using GraalVM to compile to native binaries, those start in under 10ms, and execute much faster than ClojureScript and Joker. That's a good strategy if you want to write things like a grep tool, or ls, or a linter, code formater, etc.

By contrast, one principal reason I started learning Clojure was ClojureScript. Making stuff that can run in the browser or as a browser extension is awesome for cross-platform compatibility.
If you like "functional and runs on the JVM" you might like ScalaJS too. It's a mature transpiler, and the community has rallied to ensure that all the important libraries compile both to the JVM and to JS.
Lately GraalVM can be used to compile a native binary, since Clojure compiles down to Java bytecode.

https://www.innoq.com/en/blog/native-clojure-and-graalvm/

Sometimes the trade-off of slow startup vs. having a JIT'ed VM is better, since you get a lot more performance, if you're working w/ long-lived processes.

> I certainly don't want to have to manage the JVM

Of all the things I’m unfortunate enough to have to manage in production, the JVM has never caused me any problems.

I mean, yeah, I’d like static binaries too (graal is promising but not quite there yet), but managing the JVM has nothing to do with it (footprint and startup time are my primary reasons)

> How well does the IDE warn I've made a type error before I've gone through a long compile & test iteration loop?

This doesn't really exist in a lot of dynamic languages and especially in Common Lisp, Clojure, APL, Forth, Smalltalk...etc. You write a small piece of code and interactively run it with some data...test if for some scenarios or build actual tests if you want. When it is good, add it to your actual code and you're done. You interactively test everything. Once you get used to it, anything without a REPL is like wading through quicksand. The type error would probably be caught quickly when using the REPL. In Common Lisp, when your code errors out, it drops you into the REPL and you can patch your code while it is running. Smalltalk also has this. Again, when you've seen this, a Java app crashing seems hokey.

Clojure's startup time is very slow compared to other languages, but we balance it with fully reloadable systems both on the backend or frontend.

Otherwise the speed is almost identical to the speed of native Java and native Javascript. Except when you experience the power of lazy structures, then Clojure is faster than native code.

> How well does the IDE warn I've made a type error before I've gone through a long compile & test iteration loop? How well do linters or other things work, or is there some aspect of LISP that means this is just not an issue like it is in other languages?

Yes, Lisp makes this a non issue for the most part, because the compile and test iteration loop is instantaneous and integrated fully within your IDE/Editor

Still, you get pretty decent auto-complete and static linting warns on quite a few things. For that though you'll want to use IntelliJ with Cursive or Emacs with Cider and clj-kondo + joker flywheel linters.

Edit: Let me address the performance part of your comment as well. I think using a game with 20fps as an example was to show that it could even achieve such performance. Languages like Java, C#, Clojure, Python, Ruby are normally bad choices for games as they are not performant enough. So most games are implemented in C++ with an embedded scripting language on top. So the fact a pure Clojure game can hit 20fps with lots of on screen object is actually pretty good in this case.

In general, for idiomatic Clojure code, you should expect to be within 10% the performance of pure Java. Non idiomatic Clojure can often match Java's performance, and when it can not, you can implement the hot paths in Java and use interop very easily.

For ClojureScript, performance is pretty on par with JavaScript.

Startup times are the biggest issue, if pure Java takes 80ms, Clojure will take more around 500ms to start. The issue is that each Clojure function is a Java class needing to be loaded at startup, and the JVM is very slow at loading classes. GraalVM can be used to make native images, and those will start in around 10ms, but your code might need to be adjusted a little as the native images don't yet support all runtime features.

ClojureScript startup times are pretty on par with pure JS running on Node.

> Edit: Let me address the performance part of your comment as well. I think using a game with 20fps as an example was to show that it could even achieve such performance. Languages like Java, C#, Clojure, Python, Ruby are normally bad choices for games as they are not performant enough. So most games are implemented in C++ with an embedded scripting language on top. So the fact a pure Clojure game can hit 20fps with lots of on screen object is actually pretty good in this case.

What? A hundred on screen objects is not a lot, and 20fps is a slideshow. Pure Java games regularly do 10x that (Minecraft says hello as a simple example, and it's considered badly optimized)

A "proper" C/C++ engine you'd expect 100x (thousand objects at hundreds of FPS, or things like Factorio which are 10s of thousands of objects at 60 fps).

The anecdote performance is what I'd expect from a joke language like Rockstar. I'm sure the poor performance is not Closure's fault necessarily, and it probably can fly in the right circumstances (or maybe even in a lot of circumstances). Just the anecdote's description makes Closure sound horrifically slow.

I admit it's a weird way to convince us that something is fast. To tell us you are getting 20fps without context.

Uncle Bob didn't mention any spec about his computer, he didn't say if it's 2D rendered or 3D rendered, if he's using GPU acceleration or not. So I had a look at the code for his game, and it is using a software 2D renderer. That means no GPU acceleration, it is fully rendered on the CPU. It basically uses the default processing.org 2D renderer.

Now, I don't know what spec his computer has, but software only 2D renderers are generally pretty slow. So 20fps isn't bad.

Anyways, I agree it's a weird way to show a language's performance. Like I said, Clojure will run around 10% slower than pure Java in most cases. Which is pretty fast, since Java is arguably the most performant GC language around.