◄ WORLD V · SONNY 5DART 272 · a helldive at the net

THE CLOSURE CONVERSION a function that remembers — code plus a captured environment, made explicit

A closure is a function bundled with the values of its free variables: λx. x + n that remembers n. Closure conversion is the compiler pass that makes this bundle explicit — it rewrites every function to take its captured environment as an extra argument, turning a nested, variable-capturing function into a flat top-level one plus an environment record. After conversion there are no free variables anywhere; every function is closed. This is the pass that lets functional languages with nested lambdas compile to a flat machine (dart 262's stack, dart 265's TAC) that has no notion of “capture.”

THE TECHNIQUE free variable n → passed in an explicit environment

λx. x + n with n free, closure-converted to a flat function taking an environment. The demo applies the converted form: live demo


HISTORY & CREDIT Landin 1964 · Reynolds 1972

“A closure is a mysterious runtime object.” — it is a plain pair: code, and a record of the captured values. Closure conversion writes that pair out explicitly, and afterward every function is closed — nothing to capture, nothing mysterious. cited

1964 · Peter Landin — coins closure (code + environment) for the SECD machine.
1972 · John Reynolds — defunctionalization, the sibling pass that also makes function values first-class data.
now · a standard backend pass (SML/NJ, MLton, every functional compiler).

Pass the captured environment as an argument and every function becomes closed — a flat, capture-free target the stack machine can run. The magic was only ever a pair. Landin 1964

RECOMMEND FOR I-13 env-passing application, computed

On the canonical compiler, the converted function — taking the captured n=10 as an explicit environment argument — applied at x=5 gives 15:

$ i13 run m_closure.i13 # addN(env=10, x=5), env-passing RUN OK . 12 step(s) . peak stack 3 . call depth 1 env_n = 10 result = 15
Recommend: i13 lives after closure conversion permanently. It has no closures to convert — its functions are all top-level, capture nothing, and take every value they use as an explicit argument (memory: i13 is defunctionalized by construction). The demo passes the “captured” n as an ordinary parameter because that is the only way i13 has: there are no free variables to capture. Closure conversion is the pass that gets a language to i13's flat, capture-free world; i13 simply starts there, which is why its stack machine never needs an environment pointer.