Skip to main content

Command Palette

Search for a command to run...

Programming Language in the AI era

Updated
5 min readView as Markdown
D
I created SWC, an open-source compiler project, and previously worked at Deno and Vercel. These days, I spend a lot of time building Labor0, along with Watchtower and The AI Platform at Zephyr Cloud IO.

These days, my preference is React and TypeScript for frontend development, and Go, TypeScript, then Rust for everything else.

I really like Rust, and I have used it a lot. But when I think about which language to choose for developing with AI, I rank Go highest. It seems to strike the best balance for building a fast verification loop.

Bottlenecks in the iteration loop

AI works incredibly fast. That means even a slightly slow part of the iteration loop can quickly become a bottleneck.

Developing with AI does not mean that AI’s working time—the time when the GPU is running—accounts for an overwhelmingly large share of the total. There are builds to wait for and tests to run.

This is the main reason I rank Go highest. It builds faster than Rust, and it runs things like tests faster than TypeScript. Its runtime performance is also pretty good considering how little time it takes to build.

Fast execution also means less time spent running tests. I also find that Go’s support for parallelism means test times grow much less sharply than they do with TypeScript as a project gets larger.

These days, human QA is the biggest bottleneck for me, and fast builds matter there too. When a build is slow during PR verification, QA slows down with it. Even as someone who likes Rust, I find its build times costly here.

Rust’s checks are valuable, but expensive to pay for every time

Rust catches a lot of problems. Its checks cover far more than Go’s go test -race. As I organize my thoughts for this post, I keep coming back to the feeling that Rust is both good and a bit excessive.

For most projects, I think running concurrency-related tests separately at regular intervals is enough. For something like a database, I would run them routinely, but that would mean shortening the interval. Running them every single time still seems wasteful to me.

The separate checks I have in mind are things like go test -race. I do not mean that these are equivalent to Rust’s compile-time checks. Rust catches much more.

But even recognizing the value of those checks, Rust builds are too slow for me to want to pay that cost every time. I do not think the frequency at which verification is needed always matches the frequency at which a build is needed.

Even good type inference has a cost

Rust’s type inference is a great feature. But when I wrote the code myself, I sometimes struggled to work out the types. I had to look through many files to figure out the right type.

Things were somewhat better when rust-analyzer worked well. But I developed in Rust before it existed, and even after it became available, it did not always work reliably. I still had to work without its help at times.

AI agents are so fast that I expect them to figure out types faster and better than I could. Even so, I do not feel that this gives me a reason to choose Rust when Go is available.

How hard is it to get the performance?

Rust is certainly a language with excellent performance. But using it well is much harder than people tend to think.

Imagine a senior developer unfamiliar with each language being asked by their company to build a highly parallel program in Go, TypeScript, and Rust. I would expect the Go version to be the fastest.

Handling system calls such as file reads efficiently is not particularly difficult in Go, but it is very difficult in Rust.

The difference, as I see it, is in how system calls are handled. Rust is designed to be usable in kernels, and that applies to async Rust as well. I see this design as part of what makes automatically inserting hooks around system calls difficult. Go, meanwhile, provides handling for system calls out of the box.

Unless a highly skilled developer designs the system properly, I think it is difficult to beat the handling Go already provides.

Unfriendly error messages become an advantage

Some of Go’s choices used to make me wonder why the language worked that way. In the AI era, I find those same choices helpful. Build error messages are one example.

Rust and TypeScript helpfully show code snippets in the terminal to explain what went wrong. Go tells you which line has which problem, and that is it. It does not even print every error. When I was coding by hand, I found this really frustrating.

But from an AI agent’s perspective, builds are fast, and the error messages do not consume much context either. The output I once found unfriendly has started to look like an advantage.

When developing with AI, I care about how quickly I can run the whole iteration loop, including builds, tests, and human QA. Right now, Go strikes the best balance for me.


Update: The options are limited

This seemed so obvious that I forgot to mention it when writing this post, but you have to choose a language that AI writes well. That’s why this post focuses on Rust, Go, and TypeScript.

D

At Upshot Technologies, we also focus on helping learners build practical programming and emerging technology skills through industry-oriented training and real-time projects. A great read for anyone planning their career in technology.