Performance is orthogonal to Typing

I wrote this essay as part of a discussion on the Engineering Org discord channel. Posting it here with light editing and some context.

The context for the conversation

The conversation started with @whiterose sharing this tweet from Nathan Marz:

Static typing is better for large codebases if your development team is mediocre or weak. Dynamic typing is far superior for a strong team. If you think static typing is better, then there are huge improvements you can make in how you structure your code and how you test.

This tweet blew up on the internet, and Nathan Marz later posted a tweet that was much more nuanced and less controversial:

Some general responses to the comments on my last tweet, which blew up way more than I expected:

  • Another way to phrase what I said: all else being equal, dynamically typed languages have a higher ceiling and lower floor than statically typed languages. Most of the negative responses were about that lower floor, which I agree with. This is why dynamically typed languages require more skill.
  • Many strong teams use statically typed languages, and many weak teams use dynamically typed ones. I didn't say otherwise.
  • Not all dynamically typed languages are equal. Clojure/ClojureScript are much better languages than Javascript for reasons that have nothing to do with typing, and a strong team will tend to choose a better language.
  • Static types do not reduce the number of tests that are needed in any meaningful way, as they do nothing to help sample the input space of a function/component/system and assert on its effects. At best they eliminate the occasional assertion on an output type, but that's needed a lot more rarely than you think.
  • Static typing does not give a performance advantage. If there's a performance difference between languages, it's not because of static typing.

I responded to @whiterose that he should read this nuanced tweet instead, and he had a question: "Does the last point hold true? I remember you mentioning not to use Clojure where performance is needed in IN/Clojure". What follows is my answer to his question.

Dynamic typing languages are also "typed"

Okay, let me try to expand on this.

Firstly, dynamic typed languages are also "typed". Some are strongly typed, meaning you can define the exact type that you want something to be, and the runtime will enforce a check and throw an error if types do not match. Type conversion is well-defined. For example, you cannot do 1 + "hello" in Clojure (strong typing), but you can in Javascript (weak typing).

Static typing by definition is strongly typed.

Performance benefits come from multiple places

Now let's talk about Performance Optimisation. There are many places where we can get performance benefits from, but here are the top 3 that come to my mind:

The design of the language itself.

This is the data-structure and algorithm implementations for things in the standard library – stuff we take for granted when using the language.

For example: Clojure has incredibly well-written immutable data-structures. This means you could run it in crazy multi-threaded cases but not have problems of data corruption. To compare, Scala had bugs in the standard library Map data-structure which would show up under high concurrency, leading to the wrong data existing in your hashmaps! Imagine what the reaction of the person debugging the issue must have been.

The trade-off here is performance. Clojure's data-structures are best-in-class implementations of immutable data-structures. But mutability gives huge performance gains. So if you are working on use-cases where performance is the real bottleneck, then you would need to write your own implementations of the standard data-structures for that gain. This is technically possible, but not practical.

Compiler optimisations.

This is where the compiler analyses the code you have written, and rewrites it for performance. There are a large number of tricks here, only some of which are related to typing. For example, you may have heard of loop unrolling, function inlining. These are not related to typing. But optimising variable assignment to registers, some forms of dead-code elimination, method dispatch are related to typing.

Clojure, Scala and Java are all compiled to bytecode, which runs on the JVM. But the optimisations possible are different, based on the explicit type information that is available and the implicit type information that the compiler derives. You could, if you want, give type hints to every part of the Clojure code you write. But this would be extra work, and not part of the job.

Runtime optimisations

This is what the "Runtime" does for you. For C, Rust, Zig programs, the runtime is the Operating System itself. For Clojure, Java, Scala programs, the runtime is the JVM, which is running on top of the Operating System. For Javascript, the runtime is the Browser, which is running on top of the Operating System. You see where this is going.

The JVM and V8 engines have done some incredible work like JIT, Garbage collection tuning, which makes the runtime really fast, as compared to say Python.

The runtime gives you a lot of performance. This is why the new programming language Bend is so exciting, because it's a high-level language that runs directly on the GPU, which is whole new performance unlock.

Final thoughts

Re: My offhand comment "not to use Clojure if you want performance", I hope I have explained a bit better above. Clojure can be every bit as performant as anything else that runs on the JVM. But you need to actually know what you are doing to achieve that.

That's also one of the benefits of using Rust or Zig over C. If you know what you are doing, you will be able to write the fastest stuff in C. But if two programmers both don't know how to program for performance, and one uses C and the other uses Rust/Zig, there is a better chance that the Rust/Zig guy will write the more performant code.

Caveat: I am not someone who can program high performance applications. I have never worked in a financial trading firm or a game development shop or anything like that. My knowledge is just cobbled together from my experiences as a web developer and noob systems developer. But I do think that it's good to keep performance in mind when designing applications. I want the thing I write to be fast.

Happy to learn from everyone here!

Published On: Mon, 19 Aug 2024. Last Updated On: Tue, 10 Sept 2024.