Fortran Type System
The five intrinsic types
Fortran ships exactly five built-in types; arrays, strings and user records are built on top of them.
| Type | Values it holds | Default size | Example literal |
|---|---|---|---|
integer | whole numbers | 32 bit (often kind 4) | -42 |
real | floating-point numbers | 32 bit (kind 4) | 3.14159 |
complex | two reals, real + imaginary | 2 × 32 bit | (1.0, -2.5) |
logical | .true. or .false. | compiler-dependent | .true. |
character | a fixed-length string of characters | 1 byte per char | "winter" |
Numeric types
Notable Fortran habits: division of two integers truncates (7/2 is 3), and exponentiation is a right-associative ** (2**10 is 1024). Integer/real mixes promote to real — so write 1.0_dp / 3, not 1 / 3, when you want a third.
program numeric_types
implicit none
integer :: count = 3 ! a whole number
real :: pi = 3.14159 ! single precision by default
complex :: z ! a point in the complex plane
z = (1.0, -2.5)
print *, count, pi, z
print *, 7 / 2 ! integer division: prints 3
print *, 7.0 / 2 ! real division: prints 3.5
print *, 2**10 ! exponentiation: prints 1024
end program numeric_types
KIND and precision
A real is not "a real" — it is a hardware representation chosen by the compiler from an implementation-defined set. The kind parameter is the integer tag that names one representation. Default kinds are the compiler's free choice, which is why a program that prints 32-bit floats on one compiler may print 64-bit on another. Scientific code must not rely on defaults; it must ask for a capability.
Fig. 2 — KIND selects a representation; the language never specifies bytes, only capability.
Portable kind selection
Two mechanisms do the asking. selected_real_kind(p, r) returns the kind that provides at least p decimal digits and exponent range r — usually 8 (double precision), sometimes 16. The module iso_fortran_env defines symbolic names for the compiler's concrete kinds: real32, real64, real128 and int8, int16, int32, int64. The idiomatic hook is a module parameter the whole project shares:
module kinds
! One place decides precision for the entire codebase.
implicit none
integer, parameter :: dp = selected_real_kind(15, 307) ! ~double precision
integer, parameter :: ip = selected_int_kind(9) ! ~32-bit integers
end module kinds
program precision_demo
use kinds, only: dp ! import exactly the constants we need
implicit none
real(dp) :: x ! x is double precision on every platform
real(real64) :: y ! alternative: iso_fortran_env names
x = 1.0_dp ! literal suffix: same kind as dp
y = 0.1_real64
print *, x, y
end program precision_demo
Three habits prevent the classic precision bugs: (1) define dp/ip once in a module; (2) suffix every real literal with its kind (1.0_dp); (3) never write double precision in new code — it is a legacy alias for the default real kind and silently changes meaning with compiler flags.
Logical and character types
A logical holds .true. or .false. and combines with the dotted operators .and. .or. .not. .eqv. .neqv. — the expressions lesson covers truth tables. A character variable has a compile-time length: character(len=20) :: name or the shorthand character(20). Assignment pads or truncates to fit silently, which surprises people used to resizable strings. For data of truly unknown length, Fortran 2003 added the deferred-length form character(len=:) :: s combined with allocatable, used in the strings lesson:
program characters
implicit none
character(len=12) :: short ! exactly twelve characters
character(len=:), allocatable :: long ! grows to fit
short = "hello"
long = short // " world" ! // concatenates strings
print *, len(short), trim(short), len(long)
end program characters
Trailing spaces are the price of fixed length: short holds "hello......" with seven trailing blanks, which is why output almost always passes through trim. The strings lesson systematizes these operations.
Declaration syntax in full
The complete recipe is type[, attributes] :: name[(shape)][ = init][, name2...]. Attributes — parameter, allocatable, pointer, dimension, intent, save — modify how the name behaves and are covered where they matter. Two attributes belong in every program from day one: implicit none at the unit top, and parameter for every magic number, so pi, g and steps are named once and optimized to literals.