MAPL Coding standards - GEOS-ESM/MAPL GitHub Wiki
Table of contents generated with markdown-toc
Procedure names should generally start with verbs and in snake_case. E.g., get_next_token()
.
The importance of a variable name depends on its scope. The names of module variables being the most crucial, and local variables within a procedure being the least crucial. Dummy argument names are intermediate.
Abbreviations should be avoided unless exceptionally clear and consistently applied. The common exception is a prefix to indicate "number of", e.g., n_bins
is an acceptable abbreviation of number_of_bins
. While this convention can lead to longish names, the Fortran ASSOCIATE
construct allows aliases to be used within formulae:
associate (G => universal_gravitational_constant)
f = G * m1 * m2 / r**2
end associate
Multiword variable names should use snake_case.
A variable name should be a noun, and generally be singular. The exception is for containers (arrays, lists, vectors) where plural nouns are more appropriate. For example:
real :: density_of_air
integer, allocatable :: items(:)
Note that this rule can be subtle. E.g. we use 3D arrays to represent fields, but usually refer to these fields in the singular:
type(ESMF_Field) :: humidity
Constants and FPP/CPP tokens and macros should be in ALL_CAPS. Multiword cases should use snake_case.
Array and loop indices should generally have names consisting of a single character. E.g., i
.
The names of derived types should be singular nouns and generally be written in CamelCase. E.g,:
IdentityRegridder
.
Module names should generally have a package-indicator prefix and not have a suffix. E.g., MAPL_HistoryGridComp
. The major exception to this is for the top module for a package which usually just consists of a set of USE statements. These module names should just be the package name. E.g., MAPL
.
Multiword module names should use CamelCase.
In the common case where a module declares a single public derived type, the module name should correspond to the name of that derived type. Note: module names have a package prefix but derived type names do not. E.g., the module. E.g., the module pf_DirectoryService
provides the derived type DirectoryService
.
Ideally each source file will will consist of a single program unit: subroutine, function, module, or program. The name of the file should correspond to the contained program unit. If the contained program unit is a module, the file name should not include the package-indicator prefix.
The file-type suffix should generally be .F90
indicating the use of free format and allowing the use of FPP/CPP macros.
For example, the file containing the module MAPL_HistoryGridComp
should be called HistoryGridComp.F90
Indentation of 3 characters for block constructs (if
, do
, ...) and module/type contents generally works well for Fortran. This is because the two most common block inidactors if
and ```do`` are 2 characters plus a space:
do i = 1, IM
x = elements(i)
if (x < 0) then
call do_something()
end if
end do
type :: SpecialType
private
integer :: i
real :: x
contains
procedure :: compute_y
end type
Implicit typing is not allowed. Modules must use IMPLICIT NONE
.
Module entities should use the PRIVATE
statement to make all contained entities private by default. Data components of derived types should also be default private with public overrides on rare occasions where it is necessary. Procedure declarations in a derived type (type-bound procedures) should generally be default public to allow extensions in other modules.
Public entities for a module should be declared just after the PRIVATE statement:
module FTL_MyModule
implicit none
private
public :: MyType
public :: my_proc
...
type :: MyType
...
end type
Fortran keywords should be lower case: do
,if
, integer
, contains
, module
, etc.
Use "[ ... ]" instead of "(/ ... /)". Saves characters and is much easier to read. And familar from other languages to boot.
If a procedure has any error conditions, it should be a subroutine rather than a function. There are notable exceptions however. If a procedures is best expressed as a function, but requires error handling, discuss with the development team.
Structure constructors (which are implemented as functions) must not have any error conditions. This is especially important in the context of polymorphism where implicit allocation on the client side (which then fails) results in missing the return code.
Use ">", "<", ">=", "<=", "==", and "/=" instead of ".gt.", ".lt.", ".ge.", ".le.", ".eq." and ".neq.".
Side note: Do not use "==" or "/=" for logical operands. This is not standard conforming. Correct code uses ".eqv." and ".neqv.".
The names of Fortran parameters (i.e., constants) should be in all-caps.
Any fpp/cpp preprocessor macros defined in the code should be all in all-caps.