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 (I–N = 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 / separateallocatable.- A
GOTOwith 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, assignedGOTO. Everything else is advisable, not required.
Common pitfalls
- Dropping a clause of a
GOTOcondition (.AND. ITER.LT.MAXIT) → infinite loop on non-convergence. - Translating an
EQUIVALENCEmechanically 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 executablex = 0.0_dpfor a per-call reset. - Preserving an arithmetic
IF's exact== 0branch on a real value where "small enough" was meant. - Changing
REALtoreal(dp)but leaving a single-precision literal (0.25, not0.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 attol$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, DATA
→ parameters. 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.