Coding by Hand
Rust home

What Is Programming

A program is a written-down order. The clearest place to see it is the counter at a coffee shop. You ask for a double vanilla latte. The barista does the same five moves in the same five spots every time — pull the shots, steam the milk, pump the syrup, snap the lid, slide it across. The order is the recipe. The cup, slowly filling with the right things in the right amount, is the state. Programming is writing the recipe so any barista — any machine — can hand back the same cup.

A barista's five fixed moves at the counter — the recipe a program would write down.
A barista's five fixed moves at the counter — the recipe a program would write down.

Ada Lovelace wrote the first one of these in 1843. She was working with Charles Babbage, an English mathematician who had drawn up a mechanical computer the size of a small house called the Analytical Engine. The machine was never finished while she was alive. Ada wrote a long set of notes describing how, if it were built, it could compute a tricky number series called the Bernoulli numbers. She listed the steps a punched card would feed in, one after the other, and the column of numbers each step would leave behind. The steps were her recipe. The column was her state. Today we call that recipe an algorithm, and the column the variables it sets along the way.

Donald Knuth, a Stanford professor who started writing his life's textbook in 1962, sharpened the definition. An algorithm, he said, has to be finite — it must end. It has to be definite — every step has to be unambiguous. It has to take an input and produce an output. A coffee order passes every test. You walk in (input), the barista runs the five moves (definite steps), they stop when the lid is on (finite), and you walk out with a cup (output). A daydream about coffee does not pass. There is no first step, no last step, nothing changes.

Here is the same coffee order in Rust. The cup is a thing with four parts. A function called show prints the cup so you can watch it fill up. The main function runs the steps in order, the way the barista would.

struct Cup {
    shots: u8,
    ounces_milk: u8,
    pumps_vanilla: u8,
    lid_on: bool,
}

fn show(step: &str, cup: &Cup) {
    println!(
        "after {:<14} -> shots:{} milk:{}oz vanilla:{} lid:{}",
        step, cup.shots, cup.ounces_milk, cup.pumps_vanilla, cup.lid_on
    );
}

fn main() {
    let mut cup = Cup {
        shots: 0,
        ounces_milk: 0,
        pumps_vanilla: 0,
        lid_on: false,
    };
    show("empty cup", &cup);

    cup.shots = 2;
    show("pull shots", &cup);

    cup.ounces_milk = 8;
    show("steam milk", &cup);

    cup.pumps_vanilla = 3;
    show("add vanilla", &cup);

    cup.lid_on = true;
    show("snap lid", &cup);

    println!("order ready: {}-shot latte", cup.shots);
}

The let mut cup line builds an empty cup and parks it in a variable. Every line after that changes one part of the cup. The mut keyword is Rust's way of saying you are allowed to reach back in and edit the cup later. Without mut, Rust would refuse to let you touch it twice — the language is suspicious of anything that wiggles, because programs break when state changes behind your back. You will fight that suspicion for the next several lessons. The fight is the point.

Save the file as main.rs inside a fresh folder. Compile and run it the simple way.

rustc main.rs
./main

You should see this on your screen.

after empty cup      -> shots:0 milk:0oz vanilla:0 lid:false
after pull shots     -> shots:2 milk:0oz vanilla:0 lid:false
after steam milk     -> shots:2 milk:8oz vanilla:0 lid:false
after add vanilla    -> shots:2 milk:8oz vanilla:3 lid:false
after snap lid       -> shots:2 milk:8oz vanilla:3 lid:true
order ready: 2-shot latte

Read the output top to bottom. Each line is one snapshot of the cup, taken right after a step. Line one is the empty cup. Line two has 2 shots in it but no milk. Line three has milk but no vanilla. By line five the cup is closed. The last line is the order being slid across the counter. The recipe took six lines of Rust and the state took six lines of output. Watching the columns fill in, one column per step, is the whole shape of every program you will ever write.

A question. If you delete the line cup.lid_on = true; and run it again, the last labeled snapshot would say lid:false, but would the program still print the "order ready" line? Yes. The barista hands you an open cup. Rust does not know that an open cup is wrong, because nobody told it. That is the part Ada Lovelace put in her notes and Knuth put in his definition — the machine does what you wrote, not what you meant. Forgotten steps are silent. The cup ships open.

A coffee order with five fixed steps is the easy case. The hard case is an order for 100 cups. You would not write the same five lines 100 times — you would want a way to say "run this block, once per cup, with the cup number going up each time." That missing thing is called a loop, and Rust gives you several. The next lesson cracks open the machine that turns these recipes into something the chip can actually run.