Generic Programming & Operator Overloading
Fortran (until 202Y templates) lacks true generics.
23.1 Generic interfaces (overloading by argument types)
module swap_mod
implicit none
interface swap
module procedure swap_int, swap_real, swap_char
end interface swap
contains
subroutine swap_int(a, b)
integer, intent(inout) :: a, b
integer :: t; t = a; a = b; b = t
end subroutine
subroutine swap_real(a, b)
real, intent(inout) :: a, b
real :: t; t = a; a = b; b = t
end subroutine
subroutine swap_char(a, b)
character(len=*), intent(inout) :: a, b
character(len=len(a)) :: t; t = a; a = b; b = t
end subroutine
end module swap_mod
! call swap(i, j); call swap(x, y)23.2 Operator overloading
module vector_mod
use, intrinsic :: iso_fortran_env, only: dp => real64
implicit none
type :: vec
real(dp) :: x = 0, y = 0, z = 0
contains
procedure, private :: add, sub, scale_left, dot
generic :: operator(+) => add
generic :: operator(-) => sub
generic :: operator(*) => scale_left
generic :: operator(.dot.) => dot ! user-defined operator
end type vec
interface operator(==)
module procedure vec_equal
end interface
interface assignment(=)
module procedure assign_from_array
end interface
contains
pure type(vec) function add(a, b); class(vec), intent(in) :: a, b
add = vec(a%x + b%x, a%y + b%y, a%z + b%z); end function
pure type(vec) function sub(a, b); class(vec), intent(in) :: a, b
sub = vec(a%x - b%x, a%y - b%y, a%z - b%z); end function
pure type(vec) function scale_left(a, k); class(vec), intent(in) :: a; real(dp), intent(in) :: k
scale_left = vec(a%x * k, a%y * k, a%z * k); end function
pure real(dp) function dot(a, b); class(vec), intent(in) :: a, b
dot = a%x * b%x + a%y * b%y + a%z * b%z; end function
pure logical function vec_equal(a, b); type(vec), intent(in) :: a, b
vec_equal = a%x
…23.3 Generic programming techniques (pre-templates)
Fortran (until 202Y templates) lacks true generics. Common approaches:
Generic interfaces with one specific procedure per type/kind.
Preprocessor / include templates: write the code once with macros, include it for each type.
fypp (Python-based Fortran preprocessor) — used by stdlib to generate kind-generic code:
**class(*)** unlimited polymorphism with select type (runtime generic).
Fortran 202Y template/requirement/instantiate (coming).
#:for k in ['sp', 'dp']
pure function mean_${k}$(x) result(m)
real(${k}$), intent(in) :: x(:)
real(${k}$) :: m
m = sum(x) / size(x)
end function
#:endfor23.4 Assumed-rank & select rank (F2018)
subroutine describe(a)
real, intent(in) :: a(..)
select rank (a)
rank (0); print *, "scalar", a
rank (1); print *, "vector of size", size(a)
rank (2); print *, "matrix", shape(a)
rank default; print *, "rank", rank(a)
end select
end subroutine describe