Chapter 9 — Key Takeaways (Derived Types)

A one-page reference for building your own data structures: the syntax, the intrinsics, the one rule you must not get wrong, and the piece it adds to the solver.

Defining and using a type

Syntax What it does
type :: nameend type name Define a derived type.
real(dp) :: x, y (inside) Declare components; several of one type on a line is fine.
integer :: count = 0 (inside) Component with default initialization.
type(name) :: v Declare a variable of the type.
v%comp Access a component (the percent operator).
p%pos%x Chain % for nested types.
name(a, b) or name(x=a, y=b) Structure constructor: build a value; keyword form is safer.
q = v Whole-object copy (a deep copy if components are allocatable).
type(name) :: arr(100) Array of the type; arr(i)%comp; arr%comp is a section.

Type-bound procedures (methods)

type :: circle
  real(dp) :: r
contains
  procedure :: area => circle_area     ! binding-name => module procedure
end type circle
! ...
pure function circle_area(self) result(a)
  class(circle), intent(in) :: self    ! <-- class(...), NEVER type(...)
  real(dp) :: a
  a = 3.14159265358979_dp * self%r**2
end function circle_area
! call it:  c%area()   -- c is passed automatically as self
Attribute Meaning
procedure :: m => proc Object passed as the first dummy (default pass).
procedure, pass(name) :: m => proc Object passed as the dummy called name (not necessarily first).
procedure, nopass :: m => proc Object not passed; a factory/class-level method.

The one rule to memorize

The passed-object dummy of a type-bound procedure MUST be class(...), not type(...). type(circle) :: self fails to compile; class(circle) :: self is correct. (It must be polymorphic so an extension can inherit it — Chapter 10.)

Allocatable components — value semantics for free

type :: labeled_field
  character(:), allocatable :: name       ! deferred-length string
  real(dp),     allocatable :: values(:)  ! run-time-sized array
end type
Property Allocatable component Pointer component (Ch. 11)
b = a Deep copy (independent storage) Shallow — b aliases a's data
Out of scope Auto-deallocated (no leak) Leaks unless you deallocate
Aliasing Cannot alias → optimizes better Can alias → optimizer constrained
Use it for Almost all scientific data Sharing, linked structures, C interop

Prefer allocatable components. Reach for pointer components only when you truly need sharing or self-reference (Chapter 11 makes that case).

Constructors

  • Built-in: the type name — point2d(3.0_dp, 4.0_dp). Free, positional or keyword.
  • User-defined: an interface named like the type mapping to a function that returns the type — the place to validate and allocate. The compiler picks it over the built-in by argument types.

Parameterized derived types (recognize; use with care)

type :: rvector(k, n)
  integer, kind :: k = dp    ! KIND parameter: compile-time constant (precision)
  integer, len  :: n         ! LEN parameter: fixed per object (extent)
  real(k) :: comp(n)
end type
! type(rvector(dp, 3)) :: v ;  v%n is 3

⚠️ Honest caveat: PDTs are standard (F2003/2018) but the least uniformly supported modern feature — gfortran's support has long-standing bugs. For portable code, prefer allocatable components for run-time sizing.

Intrinsics / operators used this chapter

Item Role
% Component access (and type-parameter inquiry, v%n).
allocated(v%c) Is the allocatable component allocated?
size, sum, minval, maxval Reductions over an allocatable-array component (from Ch. 5).
allocate(v%c(n)) / assignment Allocate a component (or let assignment do it).

Common pitfalls

  • Writing type(...) instead of class(...) on a passed object → compile error.
  • Indexing an unallocated allocatable component (b%v(1)=… before allocation) → run-time error.
  • Expecting a pointer component to deep-copy on = → it aliases instead (a silent bug).
  • Assuming PDTs "just work" on every compiler → they often don't; test or use allocatable components.

Numbers/rules worth memorizing

  • Derived types: Fortran 90. Type-bound procedures, PDTs, allocatable components: Fortran 2003.
  • A real(dp) is 8 bytes; a type's size is the sum of its components' sizes (plus possible padding).
  • Array of a type = Array-of-Structures (fast for whole-object loops, slow for single-field sweeps); component-arrays inside a type = Structure-of-Arrays (the reverse). Choose from the access pattern.

Project piece added this chapter

A field_t derived type in a new heat_types module, bundling nx, ny, dx, dy and real(dp), allocatable :: u(:,:), with a type-bound init (class(field_t), intent(out)). Every solver routine now passes one field_t instead of five loose variables — the data structure the rest of the book builds on (code/project-checkpoint.f90).