Chapter 6 — Teaching Notes
One-line purpose. Turn students' straight-line programs into decomposed, procedure-based software, and
drill the two habits that define robust Fortran: an intent on every argument, and arrays passed as
assumed-shape.
Key ideas to emphasize
intentis the star. This is the chapter's genuinely distinctive idea — a compiler-enforced contract most languages lack. Make it visceral: show the compiler rejecting an assignment to anintent(in)argument live. Students who leave writing an intent on every argument out of reflex have gotten the whole chapter's value.- Function vs subroutine falls out of data flow. Resist letting it become a style preference. "Returns one value, no side effects" → function; "acts on state / returns several" → subroutine. Case Study 1 is built entirely on making students derive the boundary rather than memorize it.
pure/elementalare optimization licenses, not decoration. Tie them directly to Ch. 27/33: the keyword is a promise, and the promise is what lets the compiler vectorize and parallelize. The "computeto_kelvin(t)once outside the loop" example in §6.4 is the concrete hook.- Assumed-shape is almost always right. The size travels with the array; you never pass
n. Contrast hard with legacya(*), which hides the extent and defeats bounds checking. - Explicit interface is the hidden thread. Optional, keyword, and assumed-shape all require it — which
is why we put procedures in
contains(and, in Ch. 8, modules). Name this connection explicitly.
Misconceptions to preempt
- "
intent(out)preserves the incoming value." (No — it arrives undefined; useinoutto keep it. The accumulator bug in Exercise 6.9 is the canonical trap.) - "A function can return several values like a Python tuple." (No — one result; use a subroutine.)
- "I can read an optional argument's value whether or not it was passed." (No — guard with
present.) - "
elementalmeans the argument is an array." (No — the argument is scalar; the language fans it out.) - "Assumed-shape keeps my array's 0-based bounds." (No — the dummy renumbers from 1 unless you write
a(0:).) - "Recursion is the elegant, therefore better, choice." (In numerical kernels iteration wins — no stack risk, no call overhead.)
A live demonstration (5–8 minutes)
- Compile the
swapprogram from §6.2 — it works. Then change the arguments tointent(in)and recompile; read the error aloud. Students see the contract enforced. Then fix it back toinout. - Paste an
elementalto_kelvininto Compiler Explorer (gfortran), apply it to a scalar and to an array, and note that the single definition serves both. Optional: show the vectorized loop the compiler emits.
Class-time budget (~50 min)
- 8 min: subroutine vs function; the
resultclause; the data-flow rule (§6.1). - 12 min:
intent— the three intents, the compiler enforcing them, theout-wipes-value trap (§6.2). - 8 min: optional + keyword arguments;
present(§6.3). - 8 min:
pure/elementaland the optimizer connection (§6.4). - 6 min: internal procedures, explicit interface, recursion-vs-iteration (§6.5).
- 8 min: assumed-shape vs explicit-shape vs assumed-size; the Project Checkpoint
step(§6.6 + project).
Prerequisites to review
Chapter 5 (arrays, sections, whole-array ops, allocatable, column-major) is essential — the array-argument
material and the step refactor lean on it directly. Confirm students are fluent with size, array
sections like a(2:n-1), and allocate before this chapter.
Connections
Back: Ch. 4 (control flow — the loops inside procedures), Ch. 5 (arrays). Forward: Ch. 7 (I/O, next), Ch. 8
(modules — where these procedures move and get explicit interfaces for free), Ch. 9 (field_t type in
step), Ch. 27 (the pure/elemental optimization payoff), Ch. 33 (parallelizing the pure update). The
step interface designed here is stable for the rest of the book.