For decades, I have enjoyed web application development in Ruby and observed the evolution of JavaScript from its earliest days.

As an AI developer, I started with Common Lisp, but was later forced to use Python heavily, even though I dislike its syntax. I did significant experiments in Go, Haskell and Julia (which readers of this blog are familiar with).

I’ve recently settled on the use of Rust. Here’s why:

The Rust compiler enforces strong typing and strict ownership rules. This eliminates, at compile time, many errors that would otherwise get deferred to run-time. Such errors made it more difficult to maintain older Ruby code that was crashing in production.

Python recently introduced type hints, but without enforcement, and when dealing with legacy code, there is a slippery slope to the quagmire of dynamic typing. (In my experience, type enforcement made TypeScript a huge improvement over JavaScript.)

The Rust toolchain incorporates and enforces the latest innovations in dependency management. This makes it easy to get a codebase running in a new environment.

AI researchers are to be commended for publishing their work in open source repositories (usually of Python code). However, I have wasted many hours trying to figure out which versions of Python and dependent libraries their code successfully ran on, and getting those libraries installed in my environment. UV promises to bring Python dependency management to modern standards. It is written in Rust 😀.

The smart pointer system, in combination with strict ownership rules, allow error-free management of memory allocated on the heap, but encourage allocation on the stack. And management of the stack is orders of magnitude faster than management of the heap.

I remember that garbage collection essentially freed programmers (in Java, .NET, Ruby, Python, Go, and Julia) from concerns about memory allocation. When first learning Rust, I remember thinking, “Oh 💩, I have to concern myself with the stack vs. the heap again.” Eventually, I concluded that the speed of execution and elegance of design afforded by the Rust approach are well worth the additional concern.

The rules mentioned above make the learning curve for Rust very steep. There are reports of developers utterly frustrated by their first exposure to Rust. They struggle with the compiler, especially one of its components, the borrow checker. I was one of these developers. These struggles manifest in hours spent compiling, editing, and recompiling.

What really tipped me over to Rust was the integration of an LSP server in Visual Studio Code. (This integration is available in other editors as well.) This integration gives instantaneous feedback, exposing errors while you type code.

Rust supports type inference. This makes code more concise. It makes Rust a bit easier to adopt for developers accustomed to dynamically-typed languages. But it can also make it harder to understand. LSP integration makes inferred types explicit. This aids development—without adding any unnecessary verbosity to the code. It also helps explain errors related to mismatched types.

When the Rust compiler enforces strict rules, it is able to make certain assumptions about a program and its execution. Based on these assumptions, numerous compiler optimizations become possible, whether for speed, memory usage, or even power efficiency.

I’ve spent most of my career enjoying (and indeed promoting) the benefits of object-oriented programming to manage complexity in large, long-lived systems. Along with much of the developer community, I learned to prefer composition over inheritance. In the last couple of years, I have found myself returning to my Common Lisp roots, enjoying and promoting the benefits of functional programming. (CoffeeScript emphasizes the functional aspects of JavaScript with a more concise syntax.) Here, Rust seems to strike an ideal balance. It supports algebraic data types, iterators, closures, and monads. However, unlike Haskell, a “pure functional” programming language, Rust makes it easy to put println! statements pretty much anywhere, for basic debugging 😌.

I know at least two diehards who have devoted decades-long careers to software development in C++. When I ask them why they haven’t adopted Rust, their answers are usually related to habits, an ecosystem of trusted, mature tools, and a community of relationships that allows them to produce and maintain high-quality code at large scale. This is perfectly understandable. However, for software developers with the curiosity to explore a new programming language and the opportunities it affords, I encourage you to work past the steep learning curve of Rust.