Chapter 10 — Teaching Notes
One-line purpose. Teach Fortran's full object model — inheritance, polymorphism, select type,
abstract/deferred, final — and the judgment to keep dynamic dispatch out of hot loops, then apply it to
an optional abstract solver_t framework.
Key ideas to emphasize
typevsclassis the hinge. Students conflate them. Drill it:type= monomorphic, compile-time, inlinable, the default;class= polymorphic, run-time dispatch, not inlinable, opt-in. Everything else in the chapter hangs off this distinction.- Polymorphism is indirection (the epigraph). Wheeler's line — "another level of indirection… except too many levels" — is the chapter. Dispatch is one level of indirection; used at the coarse grain it is power, sprinkled per-cell it is the "too many levels" that kill performance.
- The performance rule is non-negotiable (§10.5). Coarse grain (which solver, once per step) = free; fine grain (which cell, per element) = ruinous, because an indirect call can't be inlined and that blocks vectorization. This is the single most important takeaway for the HPC track and returns in Ch. 27.
- Abstract + deferred = a compiler-enforced contract. Contrast §10.2's zero-returning placeholder (a
silent-bug generator) with §10.4's deferred
area(a compile error if you forget). This is why abstract types exist, not just how. - The "array of boxes" idiom. A polymorphic array is uniform; heterogeneous collections need a wrapper type. This is the #1 thing students get stuck on when they first build a container.
Misconceptions to preempt
- "
classis just a faster/fanciertype." (No — it is slower per call; usetypeby default.) - "I can put different shapes in
class(shape_t) :: arr(3)." (No — one dynamic type per polymorphic array; use boxes.) - "A
finalprocedure takesclass(...)." (No —type(...); finalization isn't dispatched.) - "I need
finalto free my allocatable components." (No — they self-deallocate;finalis for files, C memory, locks.) - "
select typeis the normal way to handle different types." (Usually a design smell — prefer a deferred binding;select typeis for boundaries and genuine one-offs.) - "OOP always makes scientific code better." (Only when there's real plural variation and the dispatch is coarse-grained. Otherwise it's overhead — cycles and comprehension.)
A live demonstration (8–10 minutes)
- On Compiler Explorer (godbolt.org, gfortran), show a
type(circle_t)call toarea()— point out it inlines to a couple of instructions. Then change the handle toclass(shape_t), allocatableand show the emitted indirect call. Students needn't read assembly fluently; they can see one becomes a jump through a table. That is §10.5, wordless. - Live-build the §10.4 abstract hierarchy from §10.2's placeholder: delete the zero-returning
area, addabstract+deferred, then deliberately comment outcircle_area's binding and compile — let the class watch the compiler reject it. The error message is the lesson about contracts.
Class-time budget (~75 min for an advanced session)
- 10 min:
extendsand overriding; call-the-parent (§10.1). - 15 min:
typevsclass, dynamic dispatch, the box idiom (§10.2) — the core. - 10 min:
select typeand its design-smell warning (§10.3). - 15 min: abstract/deferred (the contract) +
final(and why you rarely need it) (§10.4). - 15 min: when OOP helps/hurts + the hot-loop rule, with the Godbolt demo (§10.5).
- 10 min: assemble the
solver_tframework; place the dispatch (§10.6 + Project Checkpoint).
Prerequisites to review
Chapter 9 (derived types, type-bound procedures, the passed-object dummy, allocatable components) and
Chapter 8 (modules, public/private) are mandatory — this chapter is meaningless without them. A 5-minute
recap of "a type-bound procedure and how self gets bound" pays for itself. Confirm students remember
column-major loop order from Chapter 5 (it justifies keeping the kernel flat).
Connections
Back: Ch. 5 (arrays/column-major), Ch. 6 (intent/passed object), Ch. 8 (modules), Ch. 9 (derived types). Forward: Ch. 11 (pointers — the indirection under polymorphism; allocatable-vs-pointer), Ch. 23 (swap integrators behind an interface), Ch. 24 (the real solver numerics), Ch. 27 (why dispatch is slow — inlining/no-aliasing), Ch. 36 (OOP in real code organization), Ch. 38 (the framework as the capstone seam), Ch. 39 (which spaced-reviews this chapter). The chapter is a natural stopping point for Scientist/HPC tracks to skim §10.3–10.4 and dwell on §10.5–10.6.