How Your Code Becomes Numbers
The whole history of coding languages was one idea being pushed further: write something a person can read, and have a machine turn it into numbers afterwards.
The turning was given a name — a compiler — and then the story moved on. This is the bit that got skipped.
Why a machine needs more than one instruction for one line
Start with a line almost too simple to bother with.
total = 4 + 7
You read that as one thought. A processor cannot, because a processor is not built to have thoughts. It is built to do one tiny thing at a time, from a very short list of tiny things it knows.
A real processor's list has a few hundred entries. Almost all of them are dull, and three of them are enough to run our line. Here is a small pretend machine with exactly those three.
It has one box it can hold a number in, and a row of numbered slots to put things away in.
| number | job | what it does |
|---|---|---|
| 1 | LOAD | put this number in the box |
| 2 | ADD | add this number to what is in the box |
| 3 | STORE | save the box into the slot with this number |
Every job is a number, and every job comes with a number. That is machine code. Not a language with words in — a list of numbers in pairs.
Doing the translation by hand
Now be the compiler. You have total = 4 + 7 and the three jobs above, and you
have to get from one to the other.
- Find the first value. It is 4, and the box is where work happens, so 4 has to get into the box. That is job 1, with the number 4.
- Find what happens to it. A plus, and a 7. The box already holds 4, so add 7 to it. That is job 2, with the number 7.
- Find where the answer goes. The name
totalis not a thing the machine has ever heard of. The compiler gives it a slot — say slot 1 — and writes that down so it uses the same slot next time. That is job 3, with the number 1.
Three pairs of numbers. Nothing else survives.
That is the part worth stopping on. The names in your program do not reach the
machine. total, hunger, playerScore — every one of them is a note the
compiler keeps for itself while it works, and throws away when it is done.
Names are for you.
Watch the numbers run
Below is our pretend machine, written in JavaScript, with [1, 4, 2, 7, 3, 1]
loaded into it — the three pairs you just worked out.
Read it and decide what it will print before you press Run. The interesting question is what number the box holds after each pair.
The for loop steps through the program two numbers at a time: a job, then the
number that goes with it.
var program = [1, 4, 2, 7, 3, 1];
var box = 0;
var slots = [0, 0, 0];
for (var i = 0; i < program.length; i = i + 2) {
var job = program[i];
var number = program[i + 1];
if (job === 1) { box = number; }
if (job === 2) { box = box + number; }
if (job === 3) { slots[number] = box; }
console.log('job ' + job + ', number ' + number + ' -> box is ' + box);
}
console.log('total is ' + slots[1]);
Nothing in that list of six numbers says "total", or "plus", or "equals". The answer still comes out right, because the order of the jobs is doing the work that the words used to do.
What a compiler is actually for
Now the reason all those languages exist becomes something you can point at.
You wrote one line. The machine got three instructions. A page of real code becomes tens of thousands of them, and every one has to be in the right order, using the right slots, with nothing left in the box that should not be there.
People did this by hand once. That is what programming was in the 1940s, and it is why punch cards mattered so much — the numbers were the program, so dropping the stack really did destroy it.
A compiler is a program that does the bookkeeping instead. It reads what you wrote, works out which jobs it needs, hands out the slots, and writes the numbers. FORTRAN existed because doing that by hand for a page of arithmetic was unbearable, and the machine is much better at it than a tired person at two in the morning.
Why the old languages will not die
Machine code is written for one kind of processor. Numbers that mean LOAD on one design may mean something else entirely on another, or nothing at all.
That is the quiet advantage the whole history was building towards. total = 4 + 7
does not belong to any particular machine. Point a different compiler at the
same line and you get different numbers for a different processor, from writing
you never had to change.
So when a program written in 1975 still runs today, it is usually not the old numbers that survived. It is the old writing, translated afresh by a compiler nobody had invented yet, for a machine nobody had built yet.
The compiler swaps the name `total` for the number of a slot. What does that tell you about names in a program?
- The machine never sees them; they are there so that people can read the code
- Names are stored alongside the numbers so the machine can look them up
- Short names make a program run faster because there is less to send
- Only names in capital letters are kept by the compiler
Every language in that history is a different answer to one question: how much of this bookkeeping can we hand to the machine? The answer has been "more" every single time, and nobody has yet found the end of it.