Why Rust?

A short piece on how Rust helped me fall in love with computers.

Why Rust?
Joyous Ferris

Tl;dr: I wanted to understand the first principles of software engineering -- how memory is laid out, how memory access patterns impact the efficiency and correctness of a program, etc. Rust doesn't try to pretend these complicated realities don't exist -- rather, the Rust compiler holds your hand as you walk through the complex jungle that is modern computing, while unsafe Rust let's you venture off the beaten path when your journey requires so.


I flirted with the idea of programming at 18. I was a freshman physics major at Kennesaw State University and decided to take an intro to programming class. The language we implemented our first Hello world's in was Java (this is the first clue things would not go well). I recall rote-memorizing just enough to stumble through the first few labs. Whenever I ran into compile-time errors, I would run to the TA's for help rather than attempt to discern the problem. This black-box view of computers led me to quickly drop the course. Once I came to realize I didn't love physics, I dropped out of college completely.

Months later, on a whim, I gave programming another try, this time with MIT's intro to programming course in Python. I didn't make it much further than a basic binary search implementation before quitting again. I still felt like I was just memorizing syntax; I was not understanding what was actually happening beneath the keystrokes and why.

An excerpt from Steve Jobs' Stanford Commencement speech propeled me through the uncertain times that followed:

"the only way to do great work is to love what you do. If you haven't found it yet, keep looking. Don't settle. As with all matters of the heart, you'll know when you find it."

With no clue where the future would lead me, and incessant pressure from family to figure things out, I kept faith that if I let my curiosities act as a compass they would not lead me astray. It was not until I began to immerse myself in hacker subculture that I began to see the beauty behind the madness. I watched shows like "Mr. Robot" and "Serial Experiments Lain", as well as movies like "Ghost in the Shell". The hacker (in the non-malicious sense of the word) ethos that "knowledge should be free to all" and "hackers should be judged by merit alone" really resonated with me, as a temporary college dropout.

Now that I had a newfound sense of community, I was back on the warpath. I began dual-booting Ubuntu and MacOS on my Macbook. Eventually I moved up to Arch Linux. I baptized myself in the command line environment -- learning how to traverse directories, troubleshooting audio issues, and only accidentally reformatting my drive twice :). This time my tool would be C++. I actually enjoyed learning C++, for the first time I felt like an actual programmer, and not a script-kiddie. The main reason I enjoyed it was because my medium of instruction had changed. Instead of begrudgingly sitting through a lecture, I read online lectures at my own pace and experimented as I saw fit. Coding began to feel more like exploring an open-world video game, unlocking new territories on my own terms. I began to understand concepts such as the difference between the stack and the heap, scopes, recursion, and encapsulation. I became fascinated at all the levels of abstraction we take for granted on a daily basis.

"Alas, a language never escapes its embryonic sac" - Alan Perlis

There I sat, blissfully atop the first peak of the Dunning-Kruger Effect Curve. High in confidence, but low in competence. The more I learned, the more I realized I did not know. I learned about how computers really worked, and soon became amazed that they worked at all. I was fascinated at all the levels of abstraction I had come to take for granted. I took a brief detour into the world of information security to try and understand why I kept hearing about so many software bugs being exploited daily. I quickly realized that by programming in C++, I was tapdancing in a minefield.

"C is short for CVE" - Anon

The C and C++ programming languages are some of the most widely used languages of all time. They still reign supreme in embedded applications where people write low-level, close to the metal programs. This is so because they allow the programmer to directly control how things are laid out in memory. This is akin to driving a drag car – it can reach top speeds, but must have its seatbelt, airbags, ceiling, backseats, and b-pillars removed to get the weight down.

"When your hammer is C++, everything begins to look like a thumb." - Steve Haflich

As I learned more and more about the information security world I came to know some of the fundamental limitations of C/C++. As a programmer, it is impossible to express your {pre/post}conditions to the C/C++ compiler with C's relatively simple type system. Since C++ is essentially C, with 40+ years of mismatched features tacked onto it, C++ is in the same boat. While a perfect programmer can write safe C/C++, humans are not perfect. As the complexity of code increases, debugging difficulty increases exponentially (particularly when attempting to debug concurrent/parallel code). A conundrum arises, is there a way to write safe code, without being slowed down by all the boring safety measures?

Buggy software is not only a cause for concern in light of bad-actors. It is important to note that unsafe, poorly designed software can have real world implications much more severe. You might be thinking "so what if $SOCIAL_MEDIA_APP crashes once a blue moon?" Many systems that we entrust our livelihoods with are running on software written by normal (e.g. non-infallible, non-genius) people. Take for example, the Therac-25 radiation therapy device from the 1980s. The dosage control code had several subtle bugs (e.g. race conditions, and arithmetic overflow) and user-unfriendly error messages -- notoriously "Malfunction 54" (no explanation attached).

Because the bugs were so elusive, the device passed it's software testing and was used on real people battling cancer. Several people were killed and severely injured by radiation poisoning after receiving dosages on par with those seen in the Fukushima disaster. The first of these accidents coincidentally occurred at the same hospital I was born at. The lives of several people were brought to unnaturally soon endings, and the survivors experienced tremendous reductions in quality of life at the hands of machines that were supposed to heal them of their ailments. Several victims were gaslit by the Therac-25 operators, as they assumed the device to be inerrant.

This, of course, is an extreme example. But, if you think about it, software impacts almost every part of our daily lives. One bug in isolation may not be that big of a deal, but these things can easily propagate and have lasting affects on our mental health, relationships, and physical health. The Therac-25 bugs would not have been present had the codebase been written in Rust, and the developers followed proper practices. This is not to say that Rust is the end-all be-all. But rather that it promotes more defensive, robust programming. We, as programmers, have important responsibilities to uphold to the general public. It is crucial that we take these duties seriously.

If Memory Safety is such a big deal, why not return to a Garbage Collected Language (e.g. Java/Python)?

GC's can be an issue if:

  • You are dealing with significant memory constraints
  • You have real-time performance constraints
  • You want reliably high performance computation and want to eliminate unnecessary overhead
  • You are dealing with more than one garbage collector (they may fight each other)

🗨️
We've experienced the perils of gerontocracy in other areas of life. One of the beauties of programming is that we can escape Kafkaesque inertia; the world of bits is a meritocracy – the best binaries win.

Enter Rust. Rust is an amazing programming language created by Graydon Hoare at Mozilla Research in 2010. According to surveys conducted by Stack Overflow, Rust has been the number 1 most loved language by developers for the last 6 years straight. The primary goals of Rust are to be performant, reliable, and productive. I've been learning and experimenting with Rust for nearly a year now. It is safe to say that I am enamored by it. I hope Rust becomes the primary language I use in my career as a Software Engineer. For readibility, I'll reserve my reasons for why I fell in love with Rust to bullet points. For more in depth reviews of rust by more experienced Rustaceans, check the "Further Readings" section at the end of this post.

"A programming language is a tool that has profound influence on our thinking habits" - Edsger Dijkstra

  • Reliability

    • Strong type system + borrow checker + traits allows compiler to uphold several important invariants:
      • Memory safety

      • Data race avoidance

      • Provably correct state machines

      • E.g. the Send Marker Trait which indicates that the type that implements Send can safely be sent across threads

      • These help prevent segfaults, data races, iterator invalidation, double free, out-of-bounds memory access, use after free, dangling pointers, etc.

    • Algebraic data types combined with exhaustive pattern matching allow for robust error handling
      • Solves the semipredicate problem
      • Rust cannot simply ignore a result, it must be dealt with by either unwrapping a success type, or handling/propagating an error type
    • Hygenic Macros
      • Solves many problems with preprocessor-based macros
  • Performance

    • Zero-cost abstractions
      • e.g. monomorphization of generics allows modularization of code with little performance overhead
      • e.g. iterators and iterator adapters replacing error-prone low level boilerplate with concise, elegant, fast solutions
    • Compiler can safely make assumptions about your code, then perform a wide range of optimizations
      • e.g. unrolling of loops
    • The programmer can decide lower-level optimization details, otherwise the compiler will do it's best to pick for you
    • Unsafe Rust is available if you need to explain invariants to the compiler that it cannot check itself
    • #![no_std] is amazing for producing small, tight embedded applications that do not rely on the standard library
  • Productivity

    • While there is a sacrifice in development speed, it is more than made up for when considering how much time is saved debugging
    • Rust's committment to stability across versions
    • Portability across architectures
    • Compiler acts as a pair-programmer
    • It is much more ergonomic to share and reuse Rust than C, both in open source contexts, as well as internally (thanks to generics)
  • Ecosystem

  • Community

"when you choose a language, you're also choosing a community." - Paul Graham

Honorable Mention: Type Inference

  • Rust's type inference helps reduce the verbosity and mental overhead that comes with such strongly typed languages
  • Types can get really ugly when dealing with async functions, especially before they are awaited. While you do explicitly have to name the types of function arguments and returned values, existential types can help tremendously
  • For example, I once was dealing with the type "AndThen<And<And<And<And<impl Filter<Extract = (), Error = Rejection> + Copy>, Map<impl Filter<Extra ct = (), Error = Infallible> + Copy, || -> Store>>, fn delete_artist(ArtistID, Store) -> impl Future<Output = Result<impl Reply, Rejection>>>" and thankfully had no clue until my editor plugin told me what it was

All in all I love that Rust let's you choose how low or high in the stack you want to program. When you need it, the compiler will act as a seat belt, often preventing accidents that you didn't even see coming. As soon as you are ready to unlock the true potential of your machine, Rust will not govern you. If you're on the road to writing great code, Rust is the vehicle for you.

"Software can be permanent ... Software's unique duality as both information and machine afford a timeless perfection and utility that stand apart from any human endeavor ... We are living in a Golden Age of software, one that will produce artifacts that will endure for generations ... Among current languages, only Rust seems to share this aspiration for permanence, with a perspective that is decidedly larger than itself." - Bryan Cantrill

Why build the next generation of software with the previous generation's programming languages?