Chapter 19 — Key Takeaways (FORTRAN 77 → Modern Translation Dictionary)

A one-page lookup for the whole chapter. Find the old construct, read across to its modern replacement, heed the one-line note. The expanded version is Appendix E.

Storage and data (§19.1)

FORTRAN 77 Modern Fortran Watch out for
COMMON /blk/ a, b a module (use), or a derived-type argument ends the "routines disagree about the block" bug
BLOCK DATA module variable initializers disappears entirely
EQUIVALENCE (bit reinterpret) transfer(x, mold) the one valid use; explicit and typed
EQUIVALENCE (save memory) separate allocatable arrays memory is no longer the constraint
EQUIVALENCE (fields of storage) a derived type named, non-overlapping components
DATA x /1.0/ real(dp) :: x = 1.0_dp initializer implicit SAVE in a procedure — see below
over-dimensioned x(MAX) + size allocatable + allocate removes the arbitrary size ceiling

Diagnose an EQUIVALENCE before translating — it does three different jobs with three different modern answers. Pick by why it is there, not what it looks like.

Control flow (§19.2)

FORTRAN 77 Modern Fortran Watch out for
backward GO TO (loop) do ... end do + exit translate every clause of the exit test
forward GO TO (leave loop) exit / exit name name the loop to leave a nested one
GO TO end-of-body cycle
GO TO out on error return / error stop
computed GO TO (a,b,c), k select case (k) add the case default the old form lacked
arithmetic IF (e) n1,n2,n3 if / else if / else the exact-== 0 branch is fragile on reals
DO 10 I=1,N ... 10 CONTINUE do i=1,n ... end do one end do per loop, even if nested
! The convergence loop -- keep BOTH clauses or risk an infinite loop
do
   iter = iter + 1
   ! ... sweep, compute diff ...
   if (diff <= tol .or. iter >= max_iter) exit   ! was: IF (DIFF.GT.TOL .AND. ITER.LT.MAXIT) GO TO 10
end do

Procedures (§19.3)

FORTRAN 77 Modern Fortran Watch out for
statement function f(x)=... internal/module pure function removed from the standard — must translate
assumed-size a(*) / a(n,*) assumed-shape a(:) / a(:,:) carries its own extent; size works
dummy args with no intent add intent(in/out/inout) not always mechanical — infer the real data flow
external proc (implicit interface) module procedure (explicit) enables checking + inlining
pure function avg4(tl, tr, tb, ta) result(m)   ! was: AVG(TL,TR,TB,TA) = 0.25*(...)
  real(dp), intent(in) :: tl, tr, tb, ta
  real(dp) :: m
  m = 0.25_dp * (tl + tr + tb + ta)
end function avg4

Form and typing (§19.4)

FORTRAN 77 Modern Fortran Watch out for
fixed-form (cols 1–72) free-form (.f.f90) a style fix — fixed-form is still legal
C/* comment in col 1 ! comment anywhere
continuation in col 6 trailing &
implicit typing (IN = integer) implicit none + declarations a correctness fix — catches typos
IMPLICIT DOUBLE PRECISION explicit real(dp) choose precision deliberately (Ch. 20)
.LT. .LE. .EQ. .NE. .GE. .GT. < <= == /= >= > old forms still valid; .EQ.==, not =

Which construct / which move

  • Old form lets the compiler not check something? → the modern replacement turns the checking back on. (COMMON → module, GOTO → labelled loops, a(*)a(:), implicit typing → implicit none.)
  • EQUIVALENCE? → ask which of three jobs first: transfer / derived type / separate allocatable.
  • A GOTO with a compound condition? → translate every clause; the dropped iteration cap is the classic infinite-loop bug.
  • Only have to translate to compile under -std=f2018? → statement functions, Hollerith, PAUSE, assigned GOTO. Everything else is advisable, not required.

Common pitfalls

  • Dropping a clause of a GOTO condition (.AND. ITER.LT.MAXIT) → infinite loop on non-convergence.
  • Translating an EQUIVALENCE mechanically without diagnosing which of its three jobs it does.
  • Trusting a declaration-initializer to reset a local each call — it has implicit SAVE; use an executable x = 0.0_dp for a per-call reset.
  • Preserving an arithmetic IF's exact == 0 branch on a real value where "small enough" was meant.
  • Changing REAL to real(dp) but leaving a single-precision literal (0.25, not 0.25_dp).

Numbers / rules worth memorizing

  • The highest-value single move is COMMON → module: it removes an entire class of silent bug.
  • The one correctness fix in "form and typing" is implicit none; fixed→free-form is style only.
  • Fixed-form is still legal; statement functions are not (removed from the current standard).
  • For the 4×4 PLATE (one edge at 100, three at 0), the converged interior is 37.5 next to the hot edge and 12.5 next to the cold ($3a-b=100$, $a=3b \Rightarrow b=12.5$), reached in 25 sweeps at tol $10^{-6}$ — the hand-check (established in Ch. 18) that a modernization preserved the physics.

Project piece advanced this chapter

The FORTRAN 77 PLATE kernel is now fully modern Fortran (code/project-checkpoint.f90): COMMON → module, statement function → pure function avg4, GOTO loop → do/exit, static arrays → real(dp) field, DATAparameters. Its numerics are unchanged — the 4×4 interior still reads 37.5000 / 12.5000, converged in 25 sweeps — closing the legacy side-quest begun in Chapter 17. The real five-point stencil arrives in Chapter 24.

Compile flag (recurring)

gfortran -std=f2018 -Wall -O2 file.f90 -o prog — unchanged. To read a legacy .f file, add -std=legacy (accepts fixed-form and the deleted features); to modernize it, translate with this dictionary and compile the result under -std=f2018.