What I Do
Provide comprehensive Fortran coding standards for MAPL development, covering:
- •Naming conventions for all program entities
- •Code structure and organization
- •Indentation and formatting rules
- •Modern Fortran practices
- •Required and prohibited patterns
When to Use Me
Use this skill when:
- •Writing new Fortran code for MAPL
- •Reviewing code for style compliance
- •Refactoring existing code
- •Learning MAPL conventions as a new contributor
- •Resolving style debates in code reviews
Naming Conventions
Procedure Names
Style: snake_case, start with verb
Examples:
subroutine get_next_token() function compute_total_mass() subroutine initialize_grid() function check_bounds()
Rationale: Verbs indicate action, snake_case improves readability
Variable Names
Style: snake_case, nouns (usually singular)
Scope matters:
- •Module variables: Most important, use full descriptive names
- •Dummy arguments: Intermediate importance, clear but can be shorter
- •Local variables: Least crucial, but still descriptive
Examples:
real :: density_of_air integer :: number_of_bins ! Or abbreviated: n_bins real :: universal_gravitational_constant type(ESMF_Field) :: humidity ! Singular for fields
Arrays/containers: Use plural nouns
integer, allocatable :: items(:) real :: temperatures(:,:) character(len=32) :: variable_names(:)
Loop indices: Single character
do i = 1, n_rows
do j = 1, n_cols
matrix(i,j) = 0.0
end do
end do
Abbreviations:
- •Avoid unless exceptionally clear and consistent
- •Exception:
n_prefix for "number of" is acceptable- •
n_binsacceptable fornumber_of_bins - •
n_levelsacceptable fornumber_of_levels
- •
Long names: Use ASSOCIATE for aliases in formulae
associate (G => universal_gravitational_constant) f = G * m1 * m2 / r**2 end associate
Constants and Macros
Style: ALL_CAPS with underscores
Examples:
integer, parameter :: MAX_STRING_LENGTH = 256 real, parameter :: PI = 3.141592653589793 integer, parameter :: UNDEFINED_VALUE = -999 ! FPP/CPP macros #define BUFFER_SIZE 1024 #define ERROR_CODE -1
Derived Type Names
Style: CamelCase, singular nouns
Examples:
type :: IdentityRegridder type :: GridFactory type :: ComponentDriver type :: StateManager
Rationale: Distinguishes types from variables, follows OOP conventions
Module Names
Style: CamelCase with package prefix
Prefix: Use package indicator (e.g., MAPL_, pf_, FTL_)
Suffix: Generally none (exception: top-level package module)
Examples:
module MAPL_HistoryGridComp module MAPL_AbstractRegridder module pf_DirectoryService module FTL_HashMap
Module/Type correspondence: When module contains single public derived type, module name corresponds to type name:
! Module: pf_DirectoryService (with package prefix)
! Type: DirectoryService (without package prefix)
module pf_DirectoryService
type :: DirectoryService
! ...
end type DirectoryService
end module pf_DirectoryService
Top-level package module: Module name is just package name (no suffix), contains only USE statements:
module MAPL use MAPL_BaseMod use MAPL_HistoryGridComp ! ... end module MAPL
File Names
Style: Match contained program unit name
Pattern: Module name WITHOUT package prefix + .F90
Examples:
! Module: MAPL_HistoryGridComp ! File: HistoryGridComp.F90 ! Module: pf_DirectoryService ! File: DirectoryService.F90 ! Module: MAPL_AbstractGridFactory ! File: AbstractGridFactory.F90
File suffix: .F90 (capital F for FPP/CPP preprocessing, free-form)
Ideal: One program unit per file (subroutine, function, module, or program)
Code Structure
Module Organization
module MAPL_MyModule
use ESMF
use MAPL_BaseMod
use pFlogger, only: logging => Logger
implicit none
private
! Public declarations immediately after private
public :: MyType
public :: my_procedure
public :: SPECIAL_CONSTANT
! Constants
integer, parameter :: BUFFER_SIZE = 1024
! Types
type :: MyType
private ! Data components private by default
integer :: internal_counter
real :: state_value
contains
procedure :: compute_result ! Type-bound procedures public
procedure :: initialize
end type MyType
contains
! Procedure implementations
subroutine my_procedure()
! ...
end subroutine my_procedure
end module MAPL_MyModule
Key Structure Rules
1. implicit none - REQUIRED
module MyModule implicit none ! MANDATORY ! ... end module
2. Default private
module MyModule implicit none private ! Everything private by default public :: OnlyThisIsPublic public :: AndThis
3. Derived type visibility
type :: MyType private ! Data components private by default integer :: internal_data real :: private_state contains procedure :: public_method ! Type-bound procedures generally public end type
Public overrides for data components allowed but rare:
type :: SpecialType private integer, public :: public_counter ! Explicit public override real :: private_value end type
Indentation
Standard: 3 spaces for block constructs and module/type contents
Rationale: Works well for Fortran where if and do are 2 characters + space
Examples:
do i = 1, n_items
x = elements(i)
if (x < 0) then
call handle_negative_value()
end if
end do
type :: MyType
private
integer :: counter
real :: value
contains
procedure :: compute
end type MyType
subroutine process_data()
integer :: i
do i = 1, n_items
if (valid(i)) then
call process_item(i)
else
call skip_item(i)
end if
end do
end subroutine process_data
Modern Fortran Practices
Use Modern Operators
Required: Use symbolic operators, not old-style
Comparison operators:
! CORRECT if (x > y) then if (a <= b) then if (value == target) then if (state /= INVALID) then ! WRONG - do not use if (x .gt. y) then if (a .le. b) then if (value .eq. target) then if (state .ne. INVALID) then
Logical operators:
! For logical operands, use equivalence operators logical :: flag1, flag2 if (flag1 .eqv. flag2) then ! CORRECT for logical if (flag1 .neqv. flag2) then ! CORRECT for logical ! DO NOT use == or /= for logical operands (not standard conforming) if (flag1 == flag2) then ! WRONG for logical if (flag1 /= flag2) then ! WRONG for logical
Array Constructors
Use: [ ... ] (modern syntax)
Avoid: (/ ... /) (old syntax)
! CORRECT integer :: values(3) values = [1, 2, 3] names = ['alpha', 'beta ', 'gamma'] ! WRONG values = (/ 1, 2, 3 /)
Rationale: Saves characters, easier to read, familiar from other languages
Fortran Keywords
Style: lowercase
! CORRECT
do i = 1, n
if (condition) then
integer :: local_var
end if
end do
module MyModule
contains
subroutine my_proc()
! WRONG
DO i = 1, n
IF (condition) THEN
END DO
MODULE MyModule
Error Handling
Procedures with Error Conditions
Rule: Use subroutines (not functions) for procedures that can fail
! CORRECT - subroutine with optional rc subroutine read_configuration(filename, config, rc) character(len=*), intent(in) :: filename type(Config), intent(out) :: config integer, optional, intent(out) :: rc ! ... can return error codes end subroutine ! Exceptions: Some procedures best expressed as functions ! Discuss with team if function requires error handling
Structure constructors: Must never have error conditions (implemented as functions)
Rationale: Polymorphism with implicit allocation can fail but can't return error code from function
See mapl-error-handling skill for comprehensive error handling patterns and macros.
Prohibited Patterns
Implicit Typing
NEVER allow implicit typing
module MyModule implicit none ! REQUIRED
Public by Default
AVOID public by default
! WRONG module MyModule implicit none ! Everything public - dangerous! ! CORRECT module MyModule implicit none private ! Safe default public :: IntendedPublicAPI
Legacy Comparison Operators
DO NOT USE: .gt., .lt., .ge., .le., .eq., .ne.
Use modern equivalents: >, <, >=, <=, ==, /=
Old Array Constructor Syntax
DO NOT USE: (/ ... /)
Use modern syntax: [ ... ]
Recommended Patterns
ASSOCIATE for Long Names
associate (G => universal_gravitational_constant, &
M => earth_mass, &
R => earth_radius)
potential = -G * M / R
end associate
Explicit Intent
subroutine process(input, output, status) integer, intent(in) :: input integer, intent(out) :: output integer, intent(inout) :: status ! When appropriate
Allocatable vs Pointer
Prefer allocatable over pointer when possible:
! PREFERRED integer, allocatable :: data(:) ! Only if pointer semantics truly needed integer, pointer :: data(:)
Complete Example
module MAPL_ExampleModule
use ESMF
use MAPL_BaseMod
implicit none
private
public :: ExampleType
public :: create_example
public :: MAX_ITERATIONS
integer, parameter :: MAX_ITERATIONS = 100
integer, parameter :: BUFFER_SIZE = 1024
type :: ExampleType
private
integer :: iteration_count
real :: convergence_tolerance
integer, allocatable :: data_values(:)
contains
procedure :: initialize
procedure :: compute_result
procedure :: check_convergence
end type ExampleType
contains
function create_example(n_values, tolerance, rc) result(example)
integer, intent(in) :: n_values
real, intent(in) :: tolerance
integer, optional, intent(out) :: rc
type(ExampleType) :: example
integer :: status
allocate(example%data_values(n_values), stat=status)
if (status /= 0) then
if (present(rc)) rc = status
return
end if
example%iteration_count = 0
example%convergence_tolerance = tolerance
if (present(rc)) rc = 0
end function create_example
subroutine initialize(this, initial_value)
class(ExampleType), intent(inout) :: this
real, intent(in) :: initial_value
integer :: i
do i = 1, size(this%data_values)
this%data_values(i) = initial_value
end do
this%iteration_count = 0
end subroutine initialize
end module MAPL_ExampleModule
Code Review Checklist
When reviewing code for style compliance:
- • All modules have
implicit none - • Module entities default private with explicit public
- • Procedures use snake_case with verb prefixes
- • Variables use snake_case, meaningful names
- • Types use CamelCase
- • Constants/macros use ALL_CAPS
- • Modern operators (
>,==) not old style (.gt.,.eq.) - • Modern array constructors
[ ]not(/ /) - • Fortran keywords in lowercase
- • Indentation is 3 spaces
- • Error-prone procedures are subroutines with optional rc
- • File name matches module name (without package prefix)
Summary
Core Principles:
- •Explicit over implicit (implicit none, default private)
- •Descriptive names over abbreviations
- •Modern syntax over legacy patterns
- •Consistency across codebase
- •Clear intent and error handling
When in doubt: Look at existing MAPL code for examples, ask in code review
Related Skills
- •
mapl-error-handling- Error handling macro patterns - •
github-workflow- Code review process - •
Code Review Checklist- Available on MAPL wiki