nativegate
← Blog

Fortran 77 to Python: what actually changes

People ask about "F77 to Python" expecting a code transformation. The honest answer: the transformation worth making is not of the source but of everything around it. This post walks the dialect itself through a modern interface, and shows what changes and what deliberately does not, using canonical F77 constructs.

Fixed-form columns: parsed away, never imposed on Python

F77 lives in columns 1–72; continuation lives in column 6. The old parse has to juggle continuation-line joining and column-1 comments; the Python caller never sees any of this. The binding's generated code handles the dialect; the interface you call is irrelevant to column discipline.

Implicit typing: decided once, not per call

Variables typed by IMPLICIT rules (I-N is INTEGER, else REAL) and DOUBLE PRECISION FUNCTION returns are exactly where naive binding patterns skip routines — our worked example's first discovery pass missed 24 of 49 routines including nine DOUBLE PRECISION functions. In the modernized surface, each routine's signature carries resolved types: the ambiguity is handled at generation time, in one place, under tests — not in each caller's head.

COMMON blocks: invisible to Python, visible to the contract

Python never sees COMMON blocks directly, which is the point. What the API contract exposes instead is their consequence: the routines are stateful, so the interface constrains how calls may interleave. A generated Fortran service holds one native call at a time per process. In exported Python land, the same rule is documentation: one session, sequential, or drift will find you.

Arrays: Python does the typing, Fortran keeps the memory

What flows is a NumPy view of original memory where feasible. The Python caller writes x = np.array([1.0, 2.0]) and the old REAL*8 X(10) convention behind it is reconciled in the generated wrapper. What doesn't change: the loan of memory, and the fact that the documented extents live in the deck rather than the type system.

What does not change — deliberately

  • The numerics: the same compiled units, the same answers, checked against a committed baseline.
  • The stateful, seat-per-process concurrency character.
  • The build dependency: a compiler is still in the production image.

"F77 to Python" done well is honest about this list: the language transition happens at the boundary only, and the promise that survives is numerical sameness with interface modernity.

Wrap one the direct way → The long version