Chapter 10 — Key Takeaways (Object-Oriented Fortran)

A one-page reference for inheritance, polymorphism, select type, abstract/deferred, and final — and the one rule that keeps them fast.

The syntax, at a glance

Construct Syntax What it does
Type extension type, extends(parent_t) :: child_t Inherit all of parent_t; add and/or override.
Parent part self%parent_t Access/​call the inherited (base) part explicitly.
Call parent's method call self%parent_t%method() Non-polymorphic call of the overridden base version.
Polymorphic variable class(base_t), allocatable :: x Holds base_t or any extension (dynamic type may vary).
Abstract type type, abstract :: t Cannot be instantiated; only extended.
Deferred binding procedure(iface), deferred :: m Contract: every concrete extension must implement m.
Abstract interface abstract interface … end interface Specifies a deferred binding's signature (needs import).
Run-time type test select type (o => x)type is / class is / class default Run a block per dynamic type.
Destructor final :: sub (arg is type(t), intent(inout)) Runs just before an object is destroyed.
Typed allocation allocate(child_t :: x) Allocate polymorphic x with dynamic type child_t.
Sourced allocation allocate(x, source = child_t(...)) Allocate and set dynamic type and value.

type vs class — the core distinction

type(t) class(t)
Kind Monomorphic Polymorphic
Dynamic type Always t t or any extension
Resolved Compile time Run time (dispatch)
Inlinable Yes No (indirect call)
Local variable Any Must be allocatable/pointer/dummy
Use it for The default; all hot-loop data Genuine run-time variation only

select type guards

  • type is (circle_t) — matches the exact dynamic type circle_t.
  • class is (shape_t) — matches shape_t or any extension; most specific match wins.
  • class default — everything unmatched.
  • Smell: a chain of type is that implements behavior should usually be a deferred binding instead.

Which construct, when

You want to… Use
Share data/behavior across related types extends (inheritance)
One interface, many interchangeable implementations abstract type + deferred binding
A variable that holds different types at run time class(...), allocatable/pointer
A mixed collection of types array of a box type wrapping class(...), allocatable :: obj
Type-specific code at a boundary (rare) select type
Clean up an unmanaged resource on destruction final procedure

Common pitfalls

  • class(t) :: x as a plain local → error; make it allocatable/pointer/dummy.
  • type(t) where t is abstract → error; abstract types cannot be instantiated.
  • final with class(t) → wrong; a finalizer takes type(t), intent(inout).
  • Positional constructor for an extended type → inherited components come first; circle_t(2.0_dp) may hit label. Use keywords: circle_t(radius = 2.0_dp).
  • Forgetting import in an abstract interface → the type/kind is "not defined"; the interface body is its own scope. Add import :: t (and use your kind, or import it).
  • A bare class(t), allocatable :: arr(:) cannot hold a mix of dynamic types → use an array of boxes.

The performance rule (memorize this)

Put polymorphism at the coarse grain; never in the hot inner loop. Dispatch once per timestep (which solver) — free. Dispatch once per cell — ruinous: an indirect call cannot be inlined, which blocks fusion and vectorization. Abstract the solver; keep the cells flat, monomorphic, and contiguous.

Numbers & facts worth keeping

  • Object orientation entered Fortran in the 2003 standard.
  • A dispatched call: order of tens of cycles, and — more costly — it blocks inlining/vectorization (Tier-2 order of magnitude; the direction is certain).
  • Allocatable components self-deallocate when their object is destroyed → you rarely need final.

Project piece added this chapter (optional/advanced track)

An abstract solver_t with a deferred step(self, fld) binding, and a heat_solver_t that extends it — so the heat solver is one interchangeable implementation behind one interface. The serial path keeps the plain heat_solver module from Chapter 8. Dispatch is once per timestep; the stencil kernel stays monomorphic. Feeds the Chapter 38 capstone as the seam where parallel and implicit solvers slot in. (See code/project-checkpoint.f90.)

Key terms

class · type extension · polymorphism · select type · abstract type · deferred binding · final · (used from earlier: derived type, component, type-bound procedure, module — Ch. 8–9).