Defining formatting styles for Fortran

For modules, I usually prepend the name of the package, I got to like this pattern at stdlib, as it feels more natural.

! src/something/foo.f90
module something_foo

    private
    public foo

contains

    subroutine foo()
        write(*,*) 'foo'
    end subroutine

end module

Parsing is hard, ambiguity, I know: but the point stills valid.
The fact that we have ambiguity in “- (binary)” and “- (unary)” didn’t stop someone to pursue that feature.
I wonder if a name in module name statements would appear in any other context other than in use statements. A more honest answer should be is harder to implement as we don’t have much help in compilers, right?

2 Likes

C++ allows namespaces and functions to have the same name. I don’t see why the Fortran standard couldn’t allow for the same.

If you go to any discourse with the intent of starting silly arguments you’ll always find something, but you won’t be contributing anything of value.

2 Likes

I guess OP understand why the code currently doesn’t work (Ex: I know the “law” is X) but is asking himself why it can’t work (Ex: what is the reasoning behind what the legislators did?).

But let’s not derail this thread, please, is about introducing a proposal for code style that is agreed upon in the community.

2 Likes

I like to put spaces around % in order to improve readability. Like in:

type(point_t) :: point

...  point % x ...

Sorry I’m writing from a mobile.

1 Like

I spend a lot of time aligning at least the function body because I believe it’s easier to read, there may be a problem with the line size (which I don’t encounter often), so I use my judgement to decide.

subroutine write(self, unit, iotype, v_list, iostat, iomsg)
    !! Represents a [[Hamiltonian]] showing each [[MatrixElement]]
    !! block on screen
    !! Example: `write(*,'(DT)') H`
    class(Hamiltonian), intent(in)    :: self
    integer,            intent(in)    :: unit
    character(*),       intent(in)    :: iotype
    integer,            intent(in)    :: v_list(:)
    integer,            intent(out)   :: iostat
    character(*),       intent(inout) :: iomsg
end subroutine
3 Likes

Personally, I don’t like aligning, exactly because of the extra work it introduces. Also if some of the dummy variables have additional attributes besides intent, such as pointer, target, save, or contiguous you have to make a decision how to deal with the extra whitespace. But as the old saying goes, de gustibus non disputandum est.

Concerning free-form styles, source code from NAG follows a very distinct style, where Fortran keywords are capitalized. You can see this in their LAPACK examples: LAPACK_Examples/dbdsdc_example.f90 at master · numericalalgorithmsgroup/LAPACK_Examples · GitHub. Other properties of this style include 2-space indentation for nested constructs, and a 4-space empty zone used for format and goto labels. I presume the style can be achieved using the NAG source file polishing tool. (Note: personally I’m not a fan of this style, as I can’t be bothered to capitalize Fortran keywords.)

4 Likes

If such a formatting style is created, please also include at least one type of preprocessors (for example, fypp). Personally, I don’t have any preference as long as the style used in one project is consistent.

2 Likes

Jane and I use the following in getting a consistent syle

nagfor =polish ch0401.f90 -alter_comments -noblank_cmt_to_blank_line -blank_line_after_decls -break_long_comment_word -format_start=100 -format_step=10 -idcase=L -indent=2 -indent_continuation=2 -indent_max=16 -keep_blank_lines -keep_comments -kwcase=L -leave_formats_in_place -margin=0 -noindent_comment_marker -noseparate_format_numbering -relational=F90+ -renumber -renumber_start=100 -renumber_step=10 -separate_format_numbering -terminate_do_with_enddo -width=132

we don’t capitalise Fortran keywords.

4 Likes

I would not do that because it looks like point and x are two separate variables and that % is operating on them. Tastes vary.

3 Likes

Some other formatting decisions are

  1. Spacing in intent(in out), end do, end if etc.
  2. The ordering of attributes in an argument declaration. All the declarations in
subroutine foo(x,y,z)
real, intent(out), allocatable, optional :: x(:)
real, allocatable, intent(out), optional :: y(:)
real, optional, intent(out), allocatable :: z(:)
end subroutine foo

are valid. Argument intent should appear in all new code, so that attribute will be present for all arguments and should appear first, but I don’t have a strong view of whether allocatable should appear before optional.

2 Likes

Different people and establishments have different preferred styles. I think it is much more valuable to be able to convert code safely between different styles See the thread:

6 Likes

That is why black, blue and other python formatters exists other than PEP8, but it would be nice to have a simple code style guide to begin with, that doesn’t rely on a tool.

True! One of the reasons I think this kind of formatting shouldn’t be in Fortran’s “PEP8”, as it is more suited for an automated tooling rather than a person typing manually (I still do it anyway, is not rational xD).

As there is no % operator, only non-fortran people (and I had this experience yesterday) would look at that and think this way, and a code style should at least presume that a person reading the code knows the language. But full disclaimer, I do both.

I like putting optional at last, intent at first, and the others in the middle, as I deem in a user perspective more important to know which argument is optional.


Gathering enough information about such variations, we could create a pool to see if a pattern emerges on “which decision would you make in order to format the following given code”, but maybe I’m overthinking it.

I’m also looking for something like that for quite some time. Also, it’s one thing to prettify an inconsistent code base and yet another to keep it consistent afterward.

Do pre-commit hooks work client-side? Are they part of the repository or only local configuration (so every developer has to enable them themselves?

It depends on how you set them up, you can do both. Technically speaking git hooks are nothing more than a script that runs on a specific git event, like commiting. There are programs, like pre-commit that do the creation and initialisation of these scripts quite painless. They also provide a CI see pre-commit.ci that automates these checks on GitHub/GitLab/etc.

A prior thread you can consider to review the preferred styles of some of the readers who responded to the poll at the time: Poll: Preferred style for tutorial code listings

3 Likes

Thanks @FortranFan that was enlightening!

So starting with the polls and the other style guides, this gives us the following list of features a fortran-lang community style guide (maybe a FEP – Fortran Enhancement Proposal? :sweat_smile:) has to cover:
( → : where possible, I added a default value candidate based on the polls)

  • names
    • case (camel/snake etc…)
      • for variables ( → snake_case)
      • for constants
      • for procedures ( → snake_case)
      • for modules, types, etc.
    • picking names
  • visual layout
    • max line width
    • indentation
      • width ( → 2 or 4, maybe even 3)
      • what (some don’t indent procedures etc.)
    • spaces within a line
      • before/after operators
      • before/after brackets
    • blank lines
    • continuation lines
      • procedure headers
      • use statements
      • function calls
      • expressions
    • general code structure
      • repeat names at end type foo etc.
      • procedure length (e.g. max number of executable statements)
      • vertical alignment?
      • (use, implicit none (no discussion in this thread, please!), private, contains, declarations, etc.)
  • keywords
    • case
    • space in end statements ( → end do)
  • comments
    • what/how to comment
    • where to put the comment

You are welcome to copy the list to reorder items and add your points.

Raw list for copying
- names
  - case (camel/snake etc...)
    - for variables ( -> snake_case)
    - for constants
    - for procedures ( -> snake_case)
    - for modules, types, etc.
  - picking names
- visual layout
  - max line width
  - indentation
    - width ( -> 2 or 4, maybe even 3)
    - what (some don't indent procedures etc.)
  - spaces within a line
    - before/after operators
    - before/after brackets
  - blank lines
  - continuation lines
    - procedure headers
    - `use` statements
    - function calls
    - expressions
  - general code structure
    - repeat names at `end type foo` etc.
    - procedure length (e.g. max number of executable statements)
    - vertical alignment?
    - (`use`, `implicit none` (no discussion in this thread, please!), `private`, `contains`, declarations, etc.)
- keywords
  - case
  - space in `end` statements ( -> `end do`)
- comments
  - what/how to comment
  - where to put the comment
2 Likes

20 posts were split to a new topic: Libraries / tools needed for creating parsers

But in out is not a list (no comma), IMHO inout is more precise.

1 Like

I agree. Software tools should have a minimum impact on the guide itself. I think that the style guide should aim to have two levels.

  1. Items that can be invariant under diff like whitespace, so it is possible to differentiate between substantive changes to code and simple format changes.
  2. Items are not diff-safe, like identifier conventions (module foo_mod vs module mod_foo vs module foo_m) that are nonetheless format changes and not substantive.

I realize that (2) is a bit ambiguous since changing the name of a module has upstream effects, but it still encompasses changes that don’t change the program itself. (You might say that (1) is simply isomorphic while (2) is weakly isomorphic. :wave:)

In any case, I believe the standard should guide the tools, except in cases where a style guide item may depend on the tool, which suggests the item is not a good candidate.

1 Like