Coding by Hand
Rust home

Why Systems Programming Still Matters

A freight train and a delivery van do different jobs. The van weaves through a neighborhood with one package at a time, stops at the door, the driver hops out, hands you a box, and drives on. The freight train hauls a hundred thousand tons of grain across three states on one tank of diesel. Both are useful. Nobody loads coal onto a Camry, and nobody runs a flower delivery on a 6,000-foot train. Programming languages split the same way. Python is the van. Rust is the freight train. This whole course is about learning to drive the train, and the first thing to understand is what the train is for.

A freight train and a delivery van — same job category, very different loads.
A freight train and a delivery van — same job category, very different loads.

The freight train was invented because a problem got too big for any other vehicle. Same with systems programming. Back in 1969, a small team at Bell Labs in New Jersey was trying to build an operating system on a refrigerator-sized minicomputer called the PDP-7. The languages of the day — assembly for speed, BCPL for convenience — both fell short. Assembly was so close to the metal that a single mistake corrupted memory and the machine had to be rebooted by hand. BCPL ran but was too slow and could not reach the hardware directly. A researcher named Dennis Ritchie wrote a new language in 1972 that sat in between. He called it C. The point of C was that it could pull boxcars — operating systems, compilers, network stacks — without melting the engine. Within five years Unix had been rewritten in it. Within fifteen, every operating system on Earth was either written in C or talking to one that was.

The bottleneck that forced C into existence is the same one that forces Rust to exist now. The bottleneck is that some problems are too heavy for a high-level language. A Python program that adds two numbers does about 300 things behind your back — it looks up what type each number is, allocates a wrapper object for the result, increments a reference count, checks for an exception, and finally hands the answer back. The wrapper is fine for a flower delivery. It is ruinous for a freight train. Operating systems, web browsers, video games, databases, the firmware in your car's brake module — all of them have to do billions of small operations per second, and the wrapper tax adds up to "the system is too slow to ship." So those programs get written in a language that does not pay the tax.

A Python int unwrapped: type header, refcount, value. A Rust u64 is just 8 bytes.
A Python int unwrapped: type header, refcount, value. A Rust u64 is just 8 bytes.

Here is the train hauling its load. The program below sums every integer from 1 to 1,000,000 in a tight loop. No allocator, no wrapper objects, no type lookup per add. Just a register holding a running total, an instruction that adds, and a counter that ticks down. Type it out and read it slowly. The whole program is 6 lines.

let n: u64 = 1_000_000;
let mut total: u64 = 0;
for i in 1..=n {
    total += i;
}
println!("summed {n} integers");
println!("total = {total}");

The number that comes back is 500,000,500,000 — the closed form for the sum of 1 through n, which is n times n plus 1 divided by 2. The compiler will not actually loop a million times if you ask it to optimize, because it can prove the answer without running the loop. That is part of the freight train's job — the compiler scouts the route and skips the parts that do not need to happen. The same loop in Python takes roughly 50 times longer at the same task, because the interpreter does the wrapper dance once per iteration.

The second cost is memory. A Python integer is not 8 bytes. It is 28 bytes, because each one carries a type header, a reference count, and the actual value, all bundled into a heap-allocated object. A Rust u64 is 8 bytes flat, sitting in a register or a cache line. Multiply by a million and the gap is real.

let rust_int_bytes = std::mem::size_of::<u64>();
let python_int_bytes: usize = 28;
println!("one u64 in Rust  = {rust_int_bytes} bytes");
println!("one int  in Py3  = {python_int_bytes} bytes (header + refcount + value)");
println!("1M of them: Rust {} MB, Python {} MB",
    rust_int_bytes * 1_000_000 / 1_048_576,
    python_int_bytes * 1_000_000 / 1_048_576,
);

Run the binary and the math shows up.

summed 1000000 integers
total = 500000500000
one u64 in Rust  = 8 bytes
one int  in Py3  = 28 bytes (header + refcount + value)
1M of them: Rust 7 MB, Python 26 MB

Twenty-six megabytes for a million Python integers, 7 megabytes for the same data in Rust. On a phone with 4 GB of RAM, that gap decides whether your app stays open in the background or gets killed when the user switches to Instagram. On a data-center server handling a million customer requests per second, that gap decides whether the company runs 1,000 machines or 4,000.

The reason a new systems language had to exist in 2010 — even though C was already there — was that C's freight train kept derailing. Linus Torvalds released the Linux kernel in 1991 written entirely in C, and Linux now runs most of the internet, but the kernel ships a stream of security advisories every month and a huge share of them are memory bugs the C compiler did not catch. The Morris worm of 1988, the first piece of internet malware, was a buffer overflow in a C program. Heartbleed in 2014 leaked the private keys of two-thirds of secure websites — a buffer overread in C code that had been audited for years. The pattern repeats: C is fast enough to drive the train, but the engineer has to watch every gauge by hand, and humans miss things.

A Bell Labs researcher at a PDP-7 in 1972, the year C was written.
A Bell Labs researcher at a PDP-7 in 1972, the year C was written.

A researcher at Mozilla named Graydon Hoare started a side project in 2006 to build a language that would pull the same loads C pulled, with the same speed, but with a compiler that refused to ship the memory bugs. He called it Rust. Mozilla took it public in 2010, hit version 1.0 in 2015, and started rewriting parts of Firefox's rendering engine in it. The crash rates fell. The frame rates did not. By 2024, Microsoft reported that roughly 70 percent of security bugs in Windows were memory bugs of the kind Rust prevents at compile time, and they began rewriting parts of the kernel in it. The Linux kernel, which Torvalds had personally guarded as C-only for 30 years, accepted its first Rust driver in 2022. Amazon's Firecracker, the thing that boots a fresh Linux microVM in 125 milliseconds every time you call an AWS Lambda function, is written in Rust. Discord rewrote its read-states service from Go to Rust and watched the latency tail collapse. The bet — that programmers will accept a stricter language if it means the freight train stops derailing — is the bet that won.

Where systems languages live in 2026 — the operating systems, browsers, and infrastructure they run.
Where systems languages live in 2026 — the operating systems, browsers, and infrastructure they run.

This is why the course you are starting matters. Python is going to remain the best tool on Earth for short scripts, data analysis, glue code between services, and quick experiments. None of that goes away. But the moment a problem grows past what one machine can chew through with the wrapper tax — a browser, a kernel, a database engine, a network stack, a game, a self-driving car — the work goes to a systems language. For the last 50 years that meant C or C++. For the next 50 it is going to mean Rust, sitting in the same seat with safer gauges.

Next lesson — what the foundations of a computer actually are, so the train's tracks make sense before you climb into the cab.