MAPL Coding standards - GEOS-ESM/MAPL GitHub Wiki

Contents

Table of contents generated with markdown-toc

1 Entity names

1.1 Procedure names

Procedure names should generally start with verbs and in snake_case. E.g., get_next_token().

1.2 Variable names

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.

1.3 Derived type names

The names of derived types should be singular nouns and generally be written in CamelCase. E.g,: IdentityRegridder.

1.4 Module names

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.

1.4 File names

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

2 Indentation

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

3 Misc

3.1 Implicit typing

Implicit typing is not allowed. Modules must use IMPLICIT NONE.

3.2 Public/private

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

3.3 Fortran keywords

Fortran keywords should be lower case: do,if, integer, contains, module, etc.

3.4 Array constructors

Use "[ ... ]" instead of "(/ ... /)". Saves characters and is much easier to read. And familar from other languages to boot.

3.5 Error handling

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.

3.6 Favor modern operators

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.".

3.7 Constants

The names of Fortran parameters (i.e., constants) should be in all-caps.

3.8 Macros

Any fpp/cpp preprocessor macros defined in the code should be all in all-caps.

⚠️ **GitHub.com Fallback** ⚠️