The Pipeline
Source code to behavior as a sequence of representations, each existing because the previous one could not answer the next question — and what is lost at every handover.
A source file is a byte sequence with no meaning of its own. What turns it into behavior is a language definition plus an implementation that honours it — and knowing which of the two you are arguing with is most of the skill.
Thirteen stages from characters to execution, each justified by a question the previous representation could not express — and the reason "phase" and "pass" are not the same word.
The three-way split exists for one reason worth stating in arithmetic: it turns `m` languages times `n` targets into `m` plus `n` implementations. What it costs is everything that does not survive the crossing into the IR.
Three implementation shapes, not two categories — and none of them is a property of a language. The sentence to stop saying is named, dismantled and replaced with a question that has an answer.
C++, Python, JavaScript, TypeScript, Java, Rust and Go, each traced through the same three questions — with the version numbers attached, because every one of these answers has changed at least once.
Do all the work before the program starts, and inherit four consequences: the fastest possible start, an unlimited optimization budget, one artifact per target, and permanent ignorance of everything only the run knows.
Every handover in the pipeline destroys something, and every tool you rely on afterwards — diagnostics, debuggers, profilers, stack traces, source maps — is an attempt to buy back one specific casualty at a specific price.
Follow `x = a + b` from characters to retired machine instructions, and watch each stage answer a question the previous representation could not even express.