Program Structure and Declarations
Every modern Fortran source file should start with program name, module name, or a similar unit header, immediately followed by implicit none, then declarations, then executable code after contains if internal procedures are present. Variable declarations follow the pattern type(kind), attributes :: name, for example real(real64), intent(in) :: x(:) for an assumed-shape real array argument, or integer, parameter :: n = 100 for a compile-time constant. Free-form source (.f90 and later) allows lowercase, meaningful names, and up to 132 columns per line, a major usability improvement over fixed-form FORTRAN 77's 72-column and all-caps conventions.
Cricket analogy: Structuring a program with implicit none right after the header is like a captain reading out fielding positions before the first ball, so nothing is ambiguous once play (execution) starts.
Control Flow and Procedures
Fortran's control constructs are if/else if/else/end if, do/end do (with optional labeled exit via exit/cycle), and select case/end select for multi-way branching, all block-structured and requiring an explicit closing keyword, which avoids the dangling-else ambiguity some C-family languages have. Procedures are either functions, which return a single value via result() or the function name, or subroutines, called with call, which communicate through intent(in)/intent(out)/intent(inout) arguments — always specify intent explicitly, since it both documents the contract and lets the compiler catch a subroutine trying to modify an intent(in) argument.
Cricket analogy: Requiring end if/end do for every block is like requiring every over to be signaled complete by the umpire before the next begins, removing any ambiguity about when one phase of play ends and the next starts.
program quick_ref
use, intrinsic :: iso_fortran_env, only: rk => real64
implicit none
integer :: i
real(rk) :: total
real(rk), allocatable :: values(:)
allocate(values(5))
values = [1.0_rk, 2.0_rk, 3.0_rk, 4.0_rk, 5.0_rk]
total = 0.0_rk
do i = 1, size(values)
if (values(i) > 3.0_rk) then
total = total + values(i)
else
cycle
end if
end do
print *, 'Sum of values > 3: ', total
deallocate(values)
end program quick_refCommon intrinsic functions worth memorizing: size(a, dim), shape(a), sum(a), matmul(a,b), dot_product(a,b), merge(true_val, false_val, mask), reshape(a, shape), allocated(a), present(optional_arg), and trim(str)/adjustl(str) for string handling.
Derived Types and Kind Constants
Derived types (Fortran's structs/classes) are declared with type :: name ... end type and can hold both data components and, with type-bound procedures, methods — enabling object-oriented patterns via type, extends(base_type) :: child_type for inheritance and class(base_type) for polymorphic dummy arguments. For numeric kinds, always import from iso_fortran_env (int32, int64, real32, real64, real128) rather than bare integer/real, since the default kind is compiler- and platform-dependent and an explicit kind makes precision requirements visible and portable across compilers like gfortran, ifx, and nvfortran.
Cricket analogy: A derived type bundling data and procedures is like a player's full profile card bundling batting average, bowling stats, and fielding position together, rather than tracking each stat in a separate disconnected list.
Never assume integer or real without a kind parameter means the same thing across compilers or platforms — default real is typically 32-bit single precision, but relying on the default rather than stating real(real64) explicitly is a common source of silent precision loss when a codebase is ported to a new compiler or platform.
- Start every unit with
implicit none; declare variables astype(kind), attributes :: name. - Use block-structured control flow (
if/end if,do/end do,select case/end select) with explicit terminators. - Prefer
subroutines with explicitintent(in)/intent(out)/intent(inout)andfunctions that return viaresult(). - Memorize core intrinsics:
size,shape,sum,matmul,dot_product,reshape,allocated,present,trim. - Use derived types with
type-bound proceduresandclass()for object-oriented, polymorphic code. - Always import numeric kinds from
iso_fortran_env(real64,int32, etc.) instead of relying on compiler defaults. - Free-form
.f90source allows lowercase, long names, and up to 132 columns, unlike fixed-form FORTRAN 77.
Practice what you learned
1. What is the recommended first executable-adjacent statement in a Fortran program or module?
2. Which intrinsic function returns the number of elements along a specified dimension of an array?
3. Why should numeric kinds be imported from `iso_fortran_env` rather than relying on bare `real` or `integer`?
4. How does a Fortran `function` typically return its result?
5. What syntax is used to declare a derived type that inherits from a base type for object-oriented Fortran?
Was this page helpful?
You May Also Like
Fortran Best Practices
Practical guidelines for writing clean, portable, and performant modern Fortran code, from type safety to array handling.
Fortran Interview Questions
Commonly asked Fortran interview questions covering language fundamentals, array semantics, and HPC concepts.
Building a Numerical Solver
A hands-on walkthrough of designing, implementing, and validating an iterative linear-equation solver in Fortran.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics