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 :: name … end 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(...), nottype(...).type(circle) :: selffails to compile;class(circle) :: selfis 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
interfacenamed 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 ofclass(...)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).