ZEN of Fortran
an opinionated coding guidelines for Fortran poor people:
- standard compliance is better than custom or extended;
- beautiful is better than ugly;
- readability counts;
- explicit is better than impl.;
- simple is better than CoMpleX;
- CoMpleX is better than c0mp1|c@ted;
- flat is better than nested;
- s p a r s e is better than dense;
- fast is better than slow:
- vector is better than loop;
- matrix is better than vector;
- strided is better than scattered;
- contiguous is better than strided;
- broadcasting is a great idea, use where possible;
- slow is better than unmaintainable;
- make it look like the math;
- special cases aren't special enough to break rules...
- although practicality beats purity;
- pure procedure is better than impure...
- although practicality beats purity again;
- private is better than public;
- errors should never pass silently...
- unless errors are explicitly silenced;
- to be continued
This list is inspired by many sources:
[1] zen of python.
[3] Modern Fortran: Style and Usage, a book by Norman S. Clerman and Walter Spector.
[4] The Fortran Company styles.
[6] European Standards For Writing and Documenting Exchangeable Fortran 90 Code.
[7] Fortran Coding Standard for the Community Atmospheric Model.
Go to TOP
This Zen of Fortran is an arbitrary guidelines for Fortraners, mainly inspired by [1]. The followings are the opinions on which we base our Zen.
Extensions to the standardized language are tempting: in general they provide many improvements (e.g. flexibility, better hardware support, special cases handling, etc...), but everything comes at a price. In particular
standard compliance codes are, in general, portable, whereas portability is, in general, lost in non standard codes.
Portable is better than specialized, a portable code is:
- free from a particular OS/hardware architecture:
- ensure long-time code's life: the OS/hardware evolution has lower impact on portable code than on non standard one (the improvement/maintenance costs are strongly reduced);
- allow easy code-enabling on new hardware: standard code can run on any architecture for which a standard compiler is provided;
- free from a particular compiler Vendor:
- standard codes are not chained to a particular Vendor, i.e. standard codes can be built by any compilers supporting the selected standard;
- the possibility to use different compilers concurrently provide a much high level cross-checking/debugging than a non portable code that can be built by only one compiler.
select your preferred standard (no matter if 77, 90-95, 2003-2008 or futures) and try to develop standard compliance codes as much as possible.
Note: compilers often provide special options to check the standard adherence of the sources compiled, e.g. Intel Fortran compiler provides -stdXX
and GNU GCC gfortran provides -std=fXX
(replace XX
with standard year YY).
Go to TOP
There is a common wrong feeling about computer codes: only the results count, no matter the form of your code is. This is wrong from many points of view, but mostly remember that
in addition to writing code for the computer, you are also writing code for humans, yourself included. The purpose of the calculations and the methods used to do so must be clear.
see [3]. This means that results count, but also readability is a value: a readable and clear (and possible concise) code can be easily debugged, improved and maintained (e.g. ported on new architecture). As a consequence, the time you spend on beautify your code is not wasted: it will reduce future works, it will allow easy collaboration with new developers, it will make easy to evolve the code itself.
The followings are some guidelines to try to develop beautiful (in the sense of readable/clear) codes:
An advice: coding styles are somehow arbitrary, 100 programmers have 101 different styles, the styles evolution is a fact. Our Zen is consequently not steady, it will evolves during time.
To improve the readability, we agree on some guidelines:
From the standard 90, Fortran language allows (and promotes) free source form.
We recommend that free source form always be used in new code.
Free source form offers a number of advantages with respect fixed source form, see [3] for a more comprehensive list. Essentially, 132 characters are better than 72. Moreover, the availability of modern wide screen allows the exploit of the new free/long line: use all the spaces you need, do not limit yourself.
The most common counter-reason to prefer short line, e.g. 80 characters see [4], is based on the eye's (in)capability to follow long line: eyes prefer vertical column order rather than horizontal row one, e.g. newspapers are typically organized with multiple columns per page. We agree on this, but this does not constitute a rule of thumb: especially for mathematical formula, it could be preferable to avoid splitting on multiple lines as much as possible.
Use your feeling: it is not mandatory to fill each 132 character of line, but it is not necessary to stay on 72.
For example, considering the following snippet:
...
associate(Ni=>self%Ni, Nj=>self%Nj, ...)
do k=1, Nk
do j=1, Nj
do i=1, Ni
do v=1, Nv
if (foo) then
select case(trim(string(i, j, k, v)))
case('good')
x_abscissa(i, j, k, v) = good_transform(abscissa=x_abscissa(i, j, k, v))
case('bad')
x_abscissa(i, j, k, v) = bad_transform(abscissa= &
x_abscissa(i, j, k, v))
case default
...
endselect
elseif (bar) then
...
else
...
endif
enddo
enddo
enddo
enddo
endassociate
...
Due to the nested loops and controls the x_abscissa
computation of good
case overcomes the 80th column, thus one is tempted to split this line as done in the bad
branch. However, if we trim out the leading withe spaces (due to the indentation) this statement is only 72 characters, thus our eyes should be still able to follow it, no matter if it overcomes the 80th column.
Old codes, say Fortran 66-77, had faced with many styles restrictions, mainly due to the fixed source form (originated from the punched cards hardwares). In particular, it was common to collapse indentation to save precious line characters. You are now free
indent as much as possible, everywhere it makes sense.
In particular, directly from [3] and [4]:
- use a consistent number of spaces when indenting code, no matter if you prefer 2, 3, 4 or another number of leading spaces;
- increase the indentation of the source code every time the data scope changes;
- indent the block of code statements within all control constructs;
- indent all the code after a named construct so the name stands out;
- break lines in logical places and indent continued lines double the number of spaces that each block is indented;
- use blank lines to separate related parts of a program.
For a example the following snippet shows good indentation.
module indented_module
implicit none
private
public :: foo
type :: foo
private
logical :: is_good = .false.
character(len=:), allocatable :: name
contains
private
procedure, public, pass(self) :: init
endtype foo
contains
pure subroutine init(self, name)
class(foo), intent(inout) :: self
character(*), optional, intent(in) :: name
if (allocated(self%name)) deallocate(self%name)
check_name: if (present(name)) then
if (len_trim(adjustl(name)) == 0) exit check_name
self%name = trim(adjustl(name))
else
self%name = 'J. Doe'
endif check_name
if (allocated(self%name)) self%is_good = .true.
return
endsubroutine init
endmodule indented_module
Fortran language allows an arbitrary number of white spaces between keywords
exploit white spaces to make readable/clear the code statements also for humans.
Note Please, avoid hard tabs.
For example the followings are considered best practices:
! white spaces around operators
if (foo > bar) then
x = (y + a / b) * z / (c + d * 0.5)
y = x * z
endif
! align similar code statements
subroutine foo (name, address, age, contact)
character(*), intent(in) :: name ! Complete name, first+surname.
character(*), intent(in) :: address ! Home address.
integer, intent(in) :: age ! Age in year, e.g. 23.
type(personal_contact), intent(out) :: contact ! Complete contact data.
...
endsubroutine foo
! place a space after all commas
x(i, j, k) = foo(i, j, k:k+1)
Go to TOP
Go to Readability
Implicit typing can boost the development of code-snippets, but
it is difficult to debug/read/understand implicit medium/large codes.
Always use implicit none statement, see [5], in:
Once for all, at the beginning of modules definition
module explicit_module
...
implicit none
...
endmodule explicit_module
Once for all, at the beginning of (main) programs definition
program explicit_program
...
implicit none
...
endprogram explicit_program
For each procedure (function and subroutine) that is not contained into a module or program, at the beginning of its definition
function explicit_function
...
implicit none
...
endfunction explicit_function
subroutine explicit_subroutine
...
implicit none
...
endsubroutine explicit_subroutine
all procedures should be contained into a module or program: old-fashioned file-libraries containing (eventually unrelated) procedures without interfaces should be avoided.
Go to TOP
Go to Explicit
to be written
Go to TOP
Go to Simple
This work is licensed under a Creative Commons Attribution 4.0 Unported License.
Go to TOP