# Fortran Best Practice Minibook

**URL:** <https://fortran-lang.discourse.group/t/fortran-best-practice-minibook/1790>\
**Category:** Announcements\
**Created:** [September 5, 2021, 10:10am UTC](https://fortran-lang.discourse.group/t/fortran-best-practice-minibook/1790 "2021-09-05T10:10:41Z")\
**Posts on this page:** 1\
**Showing post:** 85

<div class="post-metadata">

**Author:** ![Beliavsky](https://avatars.discourse-cdn.com/v4/letter/b/ba8739/32.png) [@Beliavsky](https://fortran-lang.discourse.group/u/Beliavsky)\
**Post date:** [September 20, 2021, 12:52am UTC](https://fortran-lang.discourse.group/t/fortran-best-practice-minibook/1790/85 "2021-09-20T00:52:20Z")

</div>

Here are some more suggested best practices, also listed [here](https://github.com/Beliavsky/Fortran-Best-Practices/blob/main/README.md) on GitHub, based on my own experience and reading the posted questions and codes of others. Some are matters of taste.

#### Use free source form rather than fixed source form

#### Use the .f90 suffix for free source form code

The .f90 suffix indicates free source form, not that the code conforms to the Fortran 90 standard. Don’t use suffixes such as .f95, .f03, .f08, or .f18, which not all compilers and build systems recognize as free source form Fortran files.

#### Write code in lower case

Code in lower case is more readable than code in all upper case. Comments should be capitalized as normal written language.

#### Use format strings instead of `format` statements

It is easier for the reader to understand a `write` statement if the format string is on the same line, rather than in a separate numbered format statement. If the same format string is used in multiple `write` statements, define it as a `parameter` .

#### Put functions and subroutines in modules

This enables type-checking of arguments at compile time. If this is not possible, provide an explicit interface for the procedure.

#### Put `implicit none` at the beginning of the main program or module

If this is done, it is unnecessary to write `implicit none` in each procedure.

#### Use `intent` for all procedure arguments

Any argument that is strictly an input should be declared `intent(in)` .

#### All function arguments should be `intent(in)`

A function with an `intent(out)` argument should be rewritten as a subroutine.

#### Declare functions and subroutines `pure` when possible

This tells the reader that they do not have side effects.

#### Do not have more than three or four required arguments for a procedure

Use `optional` arguments and derived types (which can store multiple entities) to reduce the number of required arguments.

#### The order of subroutine arguments should be required `intent(in)` arguments, followed by required `intent(out)` or `intent(in out)` arguments, followed by `optional` arguments

This will make it easier to call such a subroutine without naming the arguments. Argument declarations should be in the same order as the argument list.

#### Declare a function `result` on a separate line

It should appear after the declarations of function arguments but before the declarations of local variables.

#### Avoid using saved variables when possible. When they are necessary use the `save` atribute.

In a procedure, `integer :: i = 0` has a different meaning in Fortran than the analogous statement in other languages, and one should write `integer, save :: i = 0` instead to alert the reader.

#### A procedure call with many arguments should use named arguments

For example, `call reg(lhs=a,rhs=b,coeff=x,stderr=c,sse=d)` is clearer than `call reg(a,b,x,c,d)`

#### In subroutine calls, document the `intent(out)` and `intent(in out)` arguments with a comment

For example, `call sub(x1,x2,x3,x4) ! out: x3,x4` clarifies what the outputs of `sub` are.

#### Avoid `intent(in out)` arguments when possible

It was common in Fortran 77 libraries to overwrite an input matrix with output to conserve memory, but this is rarely necessary now. Instead use separate `intent(in)` and `intent(out)` array arguments.

#### Do not write a function with a `pointer` `result`

This is prone to memory leaks when the function is used in an expression.

#### Use `allocatable` arrays rather than `pointer` arrays when possible

Pointer arrays must be explicitly deallocated to avoid a memory leak.

#### At the beginning of a function or subroutine, have at least one comment line explaining what it does

#### Have a comment explaining the meaning of each procedure argument, either separately or on the same line as the argument declaration

#### When importing entities from a module, add the `only` qualifier

For example, `use m, only: func,sub` instead of `use m` . This clarifies for the reader what is being imported from each module.

#### Put a `private` statement at the beginning of a module. Only make `public` what is necessary.

This reduces namespace clashes and tells the reader what entities of a module are exported to other program units.

#### Do not put a `stop` statement before the end of the main program or a `return` statement before the end of a procedure.

Such statements are unnecessary. Use `stop` only to end a program early or `return` only to exit a procedure early.

#### Do not `deallocate` `allocatable` arrays just before the end of a program or procedure

This is unnecessary since such arrays are deallocated when they go out of scope.

#### If a derived type has `allocatable` components that have related shapes, write a subroutine to allocate them consistently

Otherwise the code will need to be updated in several places if a new allocatable component is added to the definition of the derived type. Also write subroutines to read and write the derived type.

#### When opening a file, specify the `action` as `read` or `write`

#### Do not write to standard output in a subroutine, except for error handling

It is more flexible to pass a unit number to the subroutine and to write to that unit. The unit number argument can be `optional` , and the local unit number can be set to standard output if the argument is not `present` .

#### Use local variables with a \_ suffix to shadow `optional` arguments

Set `x_` to `optional` argument `x` if it is `present` and to a default value otherwise. Consider using the `optval` function of stdlib to set such shadow variables.

#### Make a variable whose value is fixed a `parameter`

This clarifies to the reader and the compiler that the value is fixed and prevents inadvertent changes.

#### Parametrize file units with meaningful names

For example, set a `parameter` such as `data_unit` and `output_unit` and use it in `read` and `write` statements. If you use integer literals to specify the unit in `read` or `write` statements, it’s easy to mix them up.

#### Explicitly leave spaces between numbers in formatted output

Otherwise the numbers may be “mushed” together if they are larger than expected. Instead of

`write (*,"(100f12.6)") x(1:n)`

write

`write (*,"(100(1x,f12.6))") x(1:n)`

#### Use list-directed `read` to read data.

A formatted `read` depends on the data file matching the format exactly and is error-prone.

#### Indent loops, `if` blocks, and `select case` blocks

#### Label deeply nested loops so that it is clear what the `end do` corresponds to

#### Use one-line-if statements instead of if blocks when possible, to be concise

#### Short variable names should follow implicit typing rules, even though `implicit none` should be used

The reader of a Fortran program expects variables such as `i` or `i1` to be integers and `x` or `x1` to be real.

#### If a program or procedure uses a published algorithm or is derived from another code, cite the publication or code

#### Use compiler options that detect unused variables or parameters, and delete them

#### Avoid `goto` , except possibly for error handling at the end of a main program or procedure. Avoid numbered lines except to delineate a block of code for error handling.

#### Avoid the `dimension` keyword in declarations, except to declare multiple arrays of the same shape

`real :: vec(n1),mat(n1,n2)` is more concise than

`real, dimension(n1) :: vec`  
`real, dimension(n1,n2) :: mat`

However,  
`real, dimension(n1,n2) :: a,b,c` is a good use of `dimension`

#### Declare multiple variables of the same type on the same line, for concision

An exception is when you want an inline comment for each variable after its declaration.

#### Use informative loop variable names similar to the name of the upper bound

For example, `do iday=1,ndays` or `do iatom=1,natoms`

#### Don’t use array sections when the whole array is referenced

Refer to `real :: x(n)` with `x` instead of `x(:)` or `x(1:n)` . Use array sections for subsets of an array.

#### Use whole arrays in `read` and `write` statements instead of implied do loops when possible

Use `write (*,*) x` instead of `write (*,*) (x(i),i=1,n)` if they have the same effect.

#### If you are passing multiple arrays to a procedure that must have the same dimensions, consider putting them in a derived type

For example, if a subroutine accepts arguments `days(:)` , `months(:)` , `years(:)` that have a common length, probably a derived type should be defined containing (day,month,year). Then an array of that type can be passed.

#### Use explicit type conversions

For `real(kind=wp) :: x` and `integer :: i` write `x = real(i,kind=wp)` instead of `x = i` to make it clear that the conversion from integer to real is intentional. Do not use `x = dble(i)` which is less flexible.

#### Separate procedures in a module with a blank or comment line

This aids legibility.

#### Use `end subroutine foo` or `end function foo` or `end program foo` instead of just `end`

It helps the reader see what program unit is being terminated.

#### Separate terms in an arithmetic expression and the LHS and RHS with spaces

For example write `z = c*x + d*y`

#### Use integer exponentiation when possible

Write `x **2` not `x** 2.0` . The compiler may produce more efficient code for the former, which makes clear that the variable is raised to an exact integer power.

#### Beware of integer overflow

Write `(1.0/i) **n` instead of `1.0/i** n` since the denominator may overflow in the latter expression.

#### Collect physical and mathematical constants in a single module that is used where needed

Avoid defining a constant such as pi in multiple places.

#### Use instead of (//) for array constructors

This has been standard since Fortran 2003 and is supported by currently maintained compilers. The syntax is shorter and resembles that of other languages.

#### Do not rely on list-directed output having the same appearance across compilers

Use formatted output instead when this is desired.

#### Use the \* unlimited repeat count edit descriptor of Fortran 2008 instead of a large integer repeat count

The danger of `write (*,"(a,1000(1x,i0))") "abc",ivec(:)` is that `size(ivec) > 1000` will cause an error. Instead use the format string  
`"(a,*(1x,i0))"`

#### Do not rely on integer or real variables being initialized to zero

The Fortran standard does not require this. Set such variables to zero explicitly if the code depends on this.

#### Do not rely on short-circuiting in compound logical expressions

It is not safe, for example, to write `if (present(a) .and. a > 0) ainv = 1/a` . A nested `if` where the condition `present(a)` is tested first should be used instead.

#### Compile with a standard conformance option and fix code that is not conformant. Consider fixing code that uses obsolescent features.

Use for example `gfortran -std=f2018` or `ifort -stand:f18`

#### Compile with bounds-checking and other debugging options, until speed is needed for a production version.

#### Regularly compile and run your code with multiple compilers

Gfortran and Intel Fortran are both free and mature and should both be used, at the minimum. If you have a Fortran 95 code, consider testing it with g95, a mature but unmaintained Fortran 95 compiler.

---

_[View the full topic](https://fortran-lang.discourse.group/t/fortran-best-practice-minibook/1790)._
