Compilers vs Interpreters

A compiler translates your entire program to machine code before it runs. An interpreter executes your code line by line. Most modern languages blur this line.

Why It Matters

Knowing how your language executes helps you understand its performance characteristics, error behavior, and debugging tools. It also helps you pick the right language for a job.

Comparison

PropertyCompilerInterpreter
When errors appearBefore running (compile time)While running (runtime)
Execution speedFast (native machine code)Slower (overhead per line)
Startup timeSlow (must compile first)Fast (run immediately)
OutputBinary executableNo separate file
ExamplesC, Go, RustPython, Ruby, PHP

The Spectrum

Most languages don’t fit neatly into one category:

Pure Compilation                              Pure Interpretation
     ←————————————————————————————————————————→
  C     Go    Rust    Java    C#    Python    Bash
  |           |       |             |
  Compiled    Compiled  Compiled to   Compiled to
  to native   to native bytecode,     bytecode,
  code        code      JIT-compiled  interpreted
                        at runtime    by CPython VM

JIT Compilation

Just-In-Time compilation is a hybrid: the program starts interpreted, and the runtime compiles hot paths to native code on the fly.

  • Java — JVM uses JIT (HotSpot)
  • JavaScript — V8 engine uses JIT
  • Python — PyPy uses JIT (CPython does not)

Code Example

# C: compile first, then run
gcc -o hello hello.c    # produces binary
./hello                 # runs native code
 
# Go: compile and run in one step
go run main.go          # compiles to temp binary, runs it
 
# Python: interpreted (bytecode compiled transparently)
python3 script.py       # compiles to .pyc bytecode, then interprets
 
# You can see Python's compilation step:
python3 -c "import py_compile; py_compile.compile('script.py')"
# Creates __pycache__/script.cpython-312.pyc
# Python compiles to bytecode, not machine code
import dis
 
def greet(name):
    return f"Hello, {name}!"
 
dis.dis(greet)
# Shows bytecode instructions that the CPython VM interprets

Ahead-of-Time vs Just-in-Time

StrategyProsCons
AOT (C, Go)Predictable performance, no runtime overheadSlower dev cycle
JIT (Java, JS)Can optimize based on runtime dataWarm-up time, more memory
Interpreted (Python)Fastest development cycleSlowest execution