Real Worldimplementation

Four Languages, One Program

One trivial program — add two numbers, print the result — in C++, JavaScript, TypeScript and Python. Four genuinely different routes to the same six characters of output, and the differences decide what is checked, what survives to run time, and what has to be installed on the machine.

The question

The same five-line program in four languages produces the same output — so what is actually different underneath?

SourceLexingTokensParsingASTSemanticsTypedIROptimizeCodegenMachine codeLinkExecute
What the program is here

Four different final representations of one computation, and that is the entire lesson. In C++ the program ends as machine instructions in an executable, with the addition possibly performed by the compiler and never appearing at all. In Python it ends as a code object holding stack-machine bytecode, executed by a C loop. In JavaScript it ends as bytecode that may be replaced, while running, by native code specialised to types nobody declared. In TypeScript it ends as JavaScript, because the TypeScript-specific representation — a fully typed tree, the richest of the four — was deliberately thrown away before anything ran. Asking "what is this program, at the moment it computes 2 + 3" has four different answers.

What this phase may assume or do

Each route may transform the program only within what its own language defines as observable, and the four definitions differ enough to change what is permitted. C++ may delete the addition entirely under the as-if rule, because nothing observes it except the output. CPython may fold two literal constants and almost nothing else, because any name may be rebound and any operator may be user-defined between compilation and execution. A JavaScript engine may specialise the addition to integers only behind a guard that can rebuild an interpreter frame if the assumption fails. And tsc may erase a construct only if erasing it leaves run-time behavior unchanged — which is why the types go and an enum stays. Same program, four different sets of legal moves.

Key points

  • All four routes compile something before anything runs; they differ in where each one stops and when the remaining work happens.
  • C++ decides everything at build time, may delete the addition entirely, and ships an artifact for one architecture that is never reconsidered.
  • CPython compiles the whole module to bytecode first, then interprets it — and optimizes almost nothing, because dynamic rebinding makes almost nothing provable.
  • A JavaScript engine compiles to native code with types it observed rather than types anyone declared, and must be able to undo every such decision.
  • TypeScript builds the richest representation of the four and deletes it; what runs is JavaScript, so every run-time question about TypeScript is a JavaScript question.
  • The annotation a: number does not help the engine specialise anything — the engine learns the type from the value, exactly as it does without the annotation.
  • The five questions — what is checked, what is retained, what is compiled ahead, what is optimized dynamically, what runtime is required — are the ones to ask about any implementation you meet.

One program, four times

Here is the program. It adds two numbers and prints the result, and it is deliberately too small to be about anything except the pipeline. Every version produces 5.

What follows is not a ranking, and it is not a demonstration that the four are secretly the same. They are not the same. The routes differ in when checking happens, in what information survives to run time, in whether native code exists at all, in when it is produced, and in what must be present on the machine for the program to run. Those differences are the whole point, and the temptation to flatten them into "some are compiled and some are interpreted" is exactly what this module exists to remove — see [[compiler-vs-interpreter]] and [[execution-strategies]].

One thing genuinely is shared: all four compile. Every one of these routes builds at least one intermediate representation before anything executes, and three of the four generate native code at some point. The difference is *where each one stops, and when*.

The same program, four ways
// add.cpp
#include <iostream>
int main() {
  int a = 2, b = 3;
  std::cout << a + b << "\n";
}

// add.js
const a = 2, b = 3;
console.log(a + b);

// add.ts
const a: number = 2, b: number = 3;
console.log(a + b);

# add.py
a = 2
b = 3
print(a + b)

C++: all the work before, none of it after

typicalWhether 2 + 3 is folded depends on the optimization level and the compiler: at -O0 both GCC and Clang typically emit the addition and the loads, and at -O1 and above both typically fold it. The standard permits either, since only the output is observable. Any claim about what appears in the assembly needs a compiler, a version and a flag set attached — check it on Compiler Explorer rather than believing a listing, including ours.

The C++ route front-loads everything. By the time the executable exists, the types have been checked and discarded, the operators have been resolved to concrete functions, the addition has quite possibly been performed by the compiler and replaced with the literal 5, and the result is a file of machine instructions that will never be reconsidered.

The consequence people notice is that the program starts instantly and runs at full speed from the first instruction — there is no warmup, because there is nothing left to decide. The consequence people notice less is that the binary is for one architecture and one ABI: the same source must be compiled again for a different machine, and the artifact that ships is not the program you wrote in any recoverable sense.

This is also the only one of the four where the addition may legally cease to exist. Nothing in the language says an add instruction must be executed; it says the program must print 5. That is the as-if rule doing its work — see [[as-if-rule]] and [[constant-folding]].

C++ — everything decided at build timetypical
  1. Sourceyou write it
    A .cpp file plus the headers it includes.
  2. Translation unitbuild time
    One self-contained text after preprocessing, tens of thousands of lines from a five-line file.
    Self-containment: every declaration the compiler needs is now in one text.
    File boundaries, recoverable only from #line markers.
  3. Typed ASTbuild time
    A tree with every type resolved and every overload of operator<< chosen.
    Proof that the program is well-formed, and which concrete function each operator means.
  4. IR and optimizationbuild time
    Middle-end IR; a + b over two constants folds to 5.
    Transformations legal under the as-if rule.
    The addition itself, in all likelihood. There is nothing left to add at run time.
  5. Object filebuild time
    Machine code, a symbol table, relocations. main defined, std::cout undefined.
    A precise record of what this unit supplies and still needs.
    The type system. A mangled name is nearly all that crosses the boundary.
  6. Executablebuild time
    One image with symbols resolved and a program header.
    The first and only moment anything sees the whole program.
  7. Load and runload time
    A process image with the C++ standard library mapped in.
    Addresses. Then it runs at full speed immediately and is never recompiled.

Read it asEverything except the last row happens before the program exists as something runnable, and nothing after that row can change any of it. That is what "ahead of time" actually means: all the decisions are final, including the ones that turned out to be wrong for this machine or this input.

Python: a real compiler, and then a very patient interpreter

implementationCPython 3.11–3.13. Adaptive specialisation arrived in 3.11 and an experimental copy-and-patch JIT in 3.13 behind a build flag, so even within this one implementation the last row is recent and moving. PyPy reaches the same language semantics with a tracing JIT and no comparable bytecode, and GraalPy partially evaluates an AST interpreter on the JVM. The language does not require any of this.

CPython compiles the whole module before running any of it — tokens, tree, symbol table, code object — and then a loop written in C executes the resulting stack-machine bytecode. The compilation is real and is the reason a syntax error on the last line prevents the first line from running. What it is not is a compilation to machine code: no native instruction anywhere corresponds to a + b.

The addition survives all the way to run time as a bytecode instruction, and it survives as a *generic* one. BINARY_OP with the add operator must be prepared for two integers, two strings, a list and a list, or a user class whose __add__ opens a socket. Nothing earlier could narrow it, because nothing earlier knew anything: a might have been rebound between compilation and this instruction, and print might not be the built-in.

That is why the compiler optimizes so little, and it is a legality constraint rather than a shortcoming. Almost no classical transformation is provable when any name may be rebound and any operator may be overloaded. The 3.11+ adaptive interpreter's answer is to stop trying to prove things and start observing them instead — rewriting a hot instruction into a specialised form with a guard, which is a JIT's strategy applied inside an interpreter loop.

CPython — compiled to bytecode, then interpretedimplementation
  1. Sourceyou write it
    A .py file, bytes plus an encoding.
  2. Tokensbuild time
    A token stream with synthetic INDENT and DEDENT tokens.
    Block structure that no character in the file spells.
    Comments and non-significant whitespace.
  3. ASTbuild time
    A tree of ast nodes with line and column offsets — a public, documented data structure.
    Grouping and statement structure that Python's own tooling is built on.
  4. Symbol tablebuild time
    A per-scope classification of every name as local, global, cell or free.
    The only thing this pipeline decides statically — and it decides it firmly.
  5. Code objectbuild time
    A bytecode string plus constants, names and stack metadata.
    Something executable, with an explicit evaluation order.
    The tree. Positions survive only in a side table, for tracebacks.
  6. Interpretationrun time
    Frames with a value stack, executing LOAD_FAST, LOAD_FAST, BINARY_OP, CALL.
    Actual objects and actual types. The addition happens here, generically, every single time.
  7. Adaptive specialisationrun time
    Hot instructions rewritten in memory into type-specialised forms, guarded.
    A cheaper path for the types that actually occurred, discarded when the process exits.

Read it asCompare the when column with the C++ one. The same five stages exist; the boundary between "build" and "run" sits four stages earlier, and everything to the right of it is paid on every execution of every instruction rather than once.

JavaScript: compiled while it runs

typicalThis is the common shape of V8, SpiderMonkey and JavaScriptCore around 2024–2025 rather than any one of them. Tier counts and names differ and change between releases, and thresholds are tuned per engine. Nothing in ECMAScript requires tiers at all: QuickJS is a conforming engine that interprets bytecode and never generates native code, so a JavaScript program on it takes a fourth route again.

The JavaScript route looks like the Python one for the first few milliseconds and then diverges completely. The engine pre-parses to find function boundaries, fully parses a function on first call, generates bytecode, and starts interpreting immediately — so far, familiar. Then it watches. Every operation that could specialise has a feedback slot recording what types actually flowed through it.

When a function crosses a hotness threshold, an optimizing compiler recompiles it into native machine code, treating those observations as assumptions and emitting a guard for each. a + b where both operands have always been small integers becomes an integer add instruction — not because anything was declared, but because it was watched. If a later call passes a string, the guard fires, the native code is discarded and execution resumes in a lower tier at the corresponding bytecode position.

So this route produces native code, like C++, and produces it with information C++ could never have had, and pays for it in a currency C++ never spends: warmup, memory for several representations of the same function held simultaneously, and a compiler competing with the program for CPU inside the same process. Our five-line program never reaches any of that — it runs once, in the interpreter, and exits. Which is itself the lesson about short-lived processes.

A modern JavaScript engine — compilation is a run-time activitytypical
  1. Sourceload time
    UTF-16 text, usually delivered over a network.
    Nothing yet — but download and decompression are already on the critical path.
  2. Pre-parseload time
    A skeleton: function boundaries, scope shapes, syntax errors.
    Enough to start without building a tree for bodies that may never run.
  3. Full parse (per function, lazily)run time
    An AST for one function body, on first call.
    Usually discarded right after bytecode generation.
  4. Bytecoderun time
    Engine-internal VM instructions plus a feedback slot per specialisable operation.
    Something executable within milliseconds, and somewhere to record observations.
  5. Interpreted execution + profilingrun time
    The same bytecode, accumulating observed types and object shapes.
    Facts no static compiler could have: which types actually occurred here.
  6. Optimizing compilationrun time
    Native machine code for one function, specialised to those types, with guards.
    Unboxed arithmetic, inlining through monomorphic call sites, eliminated lookups.
    Generality — valid only while the guards hold.
  7. Deoptimizationrun time
    A reconstructed interpreter frame at the bytecode position the native code reached.
    A way back, without which none of the speculation would be legal.
    All the optimized work for that function.

Read it asEvery row after the first says run. There is no build step in this pipeline at all, which is why the compiler's time budget is measured in microseconds and why it must always be able to give up. It is also why a script that runs once — like ours — never sees any of the last three rows.

TypeScript, and the five questions

The TypeScript route is the JavaScript route with a build step bolted onto the front, and the honest way to describe the build step is that it produces the richest representation in this entire comparison and then deliberately throws it away. tsc parses, binds, and computes a type for every expression — at that moment it knows more about the program than any of the other three pipelines ever will — and then emits JavaScript with the annotations deleted.

That erasure is the design, not a limitation. It means the output runs on any engine, that the compiler is not a runtime dependency, that the language can describe libraries it does not control, and that the whole thing can be adopted and abandoned incrementally. It also means the annotation a: number contributes exactly nothing to how the engine specialises the addition: the engine will observe the types itself, from the values, exactly as it does for the plain JavaScript version. The two files produce the same run-time behaviour by construction — see [[type-erasure]].

Which brings the comparison to its point. Below, the five questions worth asking of any language implementation, answered for all four. Read down a column to understand one route; read across a row to see how differently four mainstream languages answer the same question. The rows are the questions to ask about the fifth language you meet.

TypeScript — the types exist only during the buildimplementation
  1. Sourceyou write it
    A .ts file.
  2. ASTbuild time
    A full-fidelity tree including type-annotation nodes with no JavaScript counterpart.
    Structure, including constructs the target language cannot express.
  3. Binderbuild time
    The tree plus symbols, merged across every file in the program.
    What each name refers to, across a whole program rather than one file.
  4. Checked programbuild time
    A type on every expression and every declaration.
    Every diagnostic the language exists to produce. The richest representation in this lesson.
  5. Emitted JavaScriptbuild time
    Ordinary JavaScript at the configured target level.
    Downlevelled syntax and the configured module format.
    The types. Annotations, interfaces, aliases and generic parameters are gone and unrecoverable from the output.
  6. Executionrun time
    Whatever the JavaScript engine makes of the emitted file — the entire previous section, again.
    Actual values, related to the declared types only by the programmer's discipline.

Read it asThe last row is the whole of the JavaScript pipeline. TypeScript does not have an execution model; it has a build step in front of somebody else's. That is why a TypeScript performance question is always a JavaScript performance question, and why a run-time type error in a TypeScript program is not a contradiction.

The five questions, answered four waystypical
QuestionC++Python (CPython)JavaScriptTypeScript
What is checked before execution?Syntax, names, types, overload resolution, template instantiation — everything the standard requires, in fullSyntax and the static local/global/cell binding of every name. No types, no attribute existence, no arity of a dynamic callSyntax only, and even that lazily per function. Nothing about typesSyntax and a full static type check across the whole program — then nothing at run time
What is retained at run time?implementationAlmost nothing: machine code, plus RTTI and exception tables where the language needs themEverything. Every object carries a type pointer, names live in dictionaries, and the source is reachable via inspectEverything the engine needs and more: object shapes, feedback vectors, bytecode, and several tiers of code at onceExactly what JavaScript retains. The declared types are not among it
What is compiled ahead of time?All of it, to machine code for one architecture and ABIAll of it, to bytecode — cached in __pycache__/ for imports, recompiled every run for the entry scriptNothing. Compilation is a run-time activity in the same processThe type checking and the syntactic transform to JavaScript. No machine code, no bytecode
What may be optimized dynamically?implementationNothing by the language implementation. The CPU still reorders and predicts underneath itHot bytecode instructions, rewritten in memory into type-specialised forms with guards, since 3.11Everything: whole functions recompiled to native code with observed types assumed, guarded, and undone on failureSame as JavaScript, on the emitted output. The annotations play no part in it
What runtime is required?A C++ standard library and the platform loader. No language runtime beyond thatA CPython interpreter of a compatible version, plus its standard library and any C extensions built against its ABIA JavaScript engine — a browser, Node, Deno, Bun — with its garbage collector and JITA JavaScript engine. The TypeScript compiler is a build-time dependency and is absent at run time

How it works

The steps, in the order the compiler takes them.

  • C++: preprocess to a translation unit, parse and type-check, lower to IR, fold and optimize, select instructions, allocate registers, assemble, link, load, execute.
  • CPython: tokenize with indentation tracking, parse to an ast tree, build a symbol table classifying every name, emit a code object, cache it for imports, and dispatch its bytecode in a C loop.
  • JavaScript: pre-parse for boundaries, parse a body on first call, emit bytecode with feedback slots, interpret while recording observed types, recompile hot functions to guarded native code, deoptimize on guard failure.
  • TypeScript: parse, bind symbols across the whole program, check types over the resulting tree, emit JavaScript with type-only constructs deleted and syntax downlevelled, and emit .d.ts separately — then hand the JavaScript to the previous route.
  • The common structure: every route builds at least one representation before execution, and each stops at the point where the remaining work is cheaper to do later or impossible to do earlier.

How it breaks

What the engineer observes when it goes wrong — not what goes wrong internally.

  • A type error is expected at run time in TypeScript because a value from a network response was declared as a User, and nothing checks it — the failure surfaces as an undefined property three functions away.
  • A Python syntax error in a function nobody calls stops the program before any output, surprising anyone who believes the file is read line by line.
  • A JavaScript benchmark reports a number ten times better than production, because the harness fed a million monomorphic inputs and the engine specialised for them.
  • A C++ program is fast on the build machine and illegal-instruction crashes on the deployment machine, because -march=native baked in instructions the target does not have.
  • A short-lived Node or Python process never reaches the fast path at all, and a change that improved steady-state throughput makes the cold case worse.
  • A performance comparison between two of these languages is presented without naming the implementations or versions, and is therefore a statement about one benchmark run and nothing else.

When it helps

  • Meeting a new language and needing to know what it actually does: the five questions place any implementation on the map in about ten minutes.
  • Debugging a class of problem to the right layer — a type error at run time in TypeScript, a warmup cliff in JavaScript, a startup cost in Python, a target mismatch in C++ — each of which is a property of the route, not of the code.
  • Explaining to a team why "just add types" does not make JavaScript faster, and why "just compile it" does not make Python faster.
  • Choosing an implementation strategy for a language or a DSL, where these four are the mainstream points on the design space — see [[execution-strategies]].

When it hurts

  • Turning this into a ranking. Each route wins the property it was designed around and loses the others, and the trivial program here exercises none of the tradeoffs that make the choice interesting.
  • Carrying the labels rather than the mechanisms. "Compiled" and "interpreted" describe none of the five rows, which is why the rows exist.
  • Assuming the four stage lists are stable. Three of them are implementation details that have changed within the last five years and will change again.

What it costs

Every one of these is paid by something.

  • Deciding everything ahead of time buys instant full-speed startup and no runtime dependency, and pays with an artifact per target, no adaptation to what the program actually does, and a build step between every edit and every test.
  • Stopping at bytecode buys trivial portability, instant startup and a compiler fast enough to run on every import, and pays with interpretive dispatch on every operation for the life of the process.
  • Deferring compilation to run time buys type information no static compiler could have, and pays with warmup, memory for several representations at once, a compiler competing with the program, and an implementation in which every optimization must be undoable.
  • Checking types and then erasing them buys portability, incremental adoption and freedom from a runtime dependency, and pays by giving up every run-time guarantee — the boundary with untyped data is unchecked and stays unchecked.
  • Comparing these four at all costs precision: every row of the matrix is true of a named implementation at a named version, and three of the four have changed materially in the last five years.

What else you could do

What a different compiler or language does instead, and when that is better.

  • Rust and Go take the ahead-of-time route with different frontends and different runtime obligations — Rust proves memory safety before LLVM sees anything, Go emits the metadata its own collector needs. See [[rust-pipeline]] and [[go-pipeline]].
  • A tree-walking interpreter stops one stage earlier than CPython, executing the typed AST directly — simpler, slower, and a perfectly legitimate implementation of the same language. See [[tree-walk-interpreter]].
  • Compiling to [[webassembly]] gives compute-heavy code a fifth route: types are known, so the engine compiles once, predictably, without the speculation machinery.
  • A gradually typed language with run-time contracts — Typed Racket, or Python with a validating layer — keeps the types at run time and pays a check per boundary crossing, which is the option TypeScript deliberately declines. See [[gradual-typing]].
  • PyPy replaces CPython's interpreter with a tracing JIT, moving Python onto something much closer to the JavaScript route, with the warmup costs that come with it.

See it for yourself

The flag, dump or tool that shows you this directly.

  • All four at once, on one program: our four-language pipeline comparison at /compilers/pipeline, which runs the same source through each route side by side.
  • C++: g++ -E, -S, -c stop after each stage; clang -Xclang -ast-dump and -S -emit-llvm show the intermediate forms; Compiler Explorer diffs two flag sets in a browser.
  • Python: python -m ast script.py, python -m dis script.py, python -X importtime script.py, and symtable.symtable(...) for the binding decisions.
  • JavaScript: node --print-bytecode, --trace-opt, --trace-deopt, and %GetOptimizationStatus(fn) under --allow-natives-syntax for the tier a function is actually in.
  • TypeScript: tsc --noEmit to check without emitting, tsc --emitDeclarationOnly for the .d.ts, and the emitted .js beside the input to see exactly what was erased.
  • The honest cross-check for any claim here: run the same measurement on two implementations of the same language. A difference means the claim was about an implementation.

Plausible wrong readings

Stated the way a confident engineer states them.

  • "Two of these are compiled and two are interpreted." All four compile. The question is what they compile to, when, and what is left to do afterwards.
  • "They all end up doing the same thing, so the differences are academic." The differences decide startup time, warmup behaviour, what fails at run time, what must be installed, and what a profiler can even attribute time to.
  • "TypeScript is faster than JavaScript because it has types." It emits JavaScript, and the engine specialises on observed values regardless. What TypeScript buys is errors before you ship, not speed after.
  • "The C++ version is fastest, so it is the best route." It is fastest to run and slowest to change, needs recompilation per target, and offers no adaptation to what the program actually does.
  • "Python is slow because it is not compiled." It is compiled, to bytecode. It is slower because the compiler cannot prove anything about a program where names rebind and operators are user-defined, so the work stays generic.

Misconceptions

The claim, and what is actually true.

The compiled languages are the fast ones.
Speed comes from what the implementation can prove or observe, not from the label. A JIT with runtime type feedback can beat a static compiler on code whose types were unknowable at build time, and an ahead-of-time compiler beats it on code whose types were known.
Adding a type annotation gives the runtime more to work with.
In TypeScript the annotation is deleted before the engine sees the file. The engine derives the same information from the values, which is why plain JavaScript and TypeScript are indistinguishable at run time.
Bytecode is a halfway house between source and machine code.
It is a complete, designed instruction set with its own trade-offs — a choice, not a compromise. And in JavaScript it is a starting point that native code is generated *from*, at run time.
A program that produces the same output is doing the same thing.
Same output, four different sets of decisions about what was checked, what survived, what was compiled and what has to be installed. The output is the only thing these four share.

Go deeper

The same idea at increasing depth. Stop wherever it stops being useful.

overview

Four languages, one tiny program. C++ works everything out before the program exists and ships machine instructions. Python turns the whole file into simple instructions for a stack machine and then runs them one at a time. JavaScript starts the same way but watches what happens and rewrites the hot parts into machine code while running. TypeScript checks the types, deletes them, and hands JavaScript to a JavaScript engine. All four compile something; they stop at different places.

practical

The five questions in the matrix are the practical takeaway, because they turn a vague question about a language into five answerable ones. When you meet a new runtime, ask them in order: what does it check before running, what does it keep at run time, what did it compile ahead of time, what can it still optimize while running, and what has to be installed. The answers predict the failure modes you will hit — run-time type errors, warmup cliffs, cold starts, deployment mismatches — before you hit any of them.

advanced

The unifying idea is that every implementation chooses where to place a boundary between what is decided and what is deferred, and every choice buys information at the price of flexibility, or the reverse. C++ decides everything and can therefore assume everything and adapt to nothing. A JavaScript engine defers everything and can therefore observe everything and must be able to undo everything, which is why its most difficult component is not the optimizer but the deoptimizer. CPython places the boundary early and then discovers, twenty years later, that it can move a little of it back with adaptive specialisation. TypeScript is the interesting case because it places the boundary *outside the running program entirely*: the information is produced, used to reject programs, and then discarded on purpose. That is a real design position — the type system exists to prevent code from shipping, not to make it run — and it is the reason TypeScript can describe libraries it does not control, run on engines that have never heard of it, and be removed from a project one file at a time.

How much this depends on

Nothing in this domain is true of every compiler. These say how much.

implementationThe four stage lists describe Clang or GCC, CPython 3.11–3.13, V8/SpiderMonkey/JavaScriptCore around 2024–2025, and tsc 5.x. Each has other implementations that take genuinely different routes — PyPy, GraalPy and MicroPython for Python; QuickJS for JavaScript; esbuild and Node's type stripping for TypeScript; and MSVC with a different object format and mangling for C++. Change the implementation and this comparison changes with it.
typicalWhether the addition is folded away in the C++ version depends on the optimization level: at -O0 the addition and the loads are typically emitted, and at -O1 and above they typically are not. The standard requires only the output, so both are conforming, and the same is true of every assembly listing in this domain.
specWhat each language guarantees is stable in a way none of the pipelines are: C++ specifies observable behavior and the as-if rule, ECMAScript specifies semantics and says nothing about tiers, and TypeScript specifies that type-only constructs are erased. Every guarantee in the matrix that is not one of those is an implementation fact with a version attached.
simplifiedThe program is deliberately trivial and therefore exercises none of the cases that make these routes interesting: no generics, no dynamic dispatch, no polymorphic call site, no allocation, no I/O beyond one line. A realistic program would widen every difference in the matrix, particularly the middle two rows.

If you were asked this in an interview

  • The same program in C++, Python, JavaScript and TypeScript. For each: what is checked before it runs, and what is left at run time?
  • Does a TypeScript annotation help the JavaScript engine optimize? Defend the answer.
  • Which of these four could delete the addition entirely, and what makes that legal?
  • You are handed a language you have never seen. What five questions place its implementation on this map?

Connections

OS & Networkingprogram-vs-process
Domains that do not exist yet
  • Programming Languages & Runtime Internals — Object representation and garbage collection in each of the four runtimes
    The middle row of the matrix — what is retained at run time — is a question about object models, and the answers differ as much as the pipelines do. This lesson stops at the handover to each runtime; what those runtimes hold and how they reclaim it is owned there.
  • Observability & Performance Engineering — Measuring across implementations with different warmup and startup behaviour
    Every comparison in this lesson is only as good as the measurement behind it, and measuring four runtimes fairly — warmup, steady state, cold start, the same workload — is a discipline of its own that this domain does not own.