Compiled vs Interpreted Code
Computers run machine instructions, so source code has to be translated first. A compiler translates it ahead of time; an interpreter reads and executes it as the program runs. Many languages use a mix of both.
Three models
- Compiled to machine code: a compiler turns the whole program into an executable for one platform before it runs. Examples: C, C++, Go, Rust. You ship the binary.
- Interpreted: an interpreter reads the source (or an internal form of it) and executes it directly. Examples: Python, JavaScript, Ruby, PowerShell and Bash scripts. You ship source and need the interpreter installed.
- Compiled to an intermediate form, then run by a virtual machine: Java and C# compile to bytecode, which a runtime executes, often compiling hot parts to machine code on the fly (JIT, just-in-time compilation).
The boundaries blur. The standard Python (CPython) first compiles source to bytecode, then interprets that. Browser JavaScript engines use JIT compilation. TypeScript is “transpiled” to JavaScript, a source-to-source translation.
Why it matters day to day
| Aspect | Compiled ahead of time | Interpreted |
|---|---|---|
| Errors | Many found at build time | Many found only when that line runs |
| Running | Build, then run the output | Run the source directly |
| Distribution | Per-platform binary | Source plus runtime |
| Feedback loop | Needs a rebuild | Quick to try changes |
Type checking is a separate question. Static checking exists in both worlds, for example through TypeScript or Python type hints.
This is why “build” and “run” are separate steps in many projects (see Build vs Run vs Deploy). It also explains “works on my machine”: a binary built for Windows will not run on Linux, and an interpreted program can fail when the runtime version differs.
Linker, runtime and build types
- A linker joins compiled pieces and libraries into one executable.
- The runtime is the supporting code a program needs while running.
- A debug build and a release build are the same code compiled with different settings.
Try it
Pick one compiled and one interpreted language you have installed. For each, find the command that runs a “hello world” program, what files it produces and what a colleague needs installed to run it. In Python, also inspect the bytecode: python -c "import dis; dis.dis(lambda x: x + 1)".
Common mistakes
- Assuming a binary built for Windows will run on Linux.
- Assuming an interpreted program runs the same on every runtime version.
- Treating static type checking as something only compiled languages have.
Check yourself
- What does a JIT compiler do?
- Why can an interpreted program fail on a colleague's machine even though the source is identical?
- What does a linker do?