Defining formatting styles for Fortran

As far as I know Fortran does not have any defined code formatting styles (not to be confused with FORMAT specifiers for I/O). All present formatting tools impose whatever formatting style the authors deem important, which is not optimal.
Do you think it would be worth defining certain styles, similar to clang’s GNU, LLVM, Mozilla, etc. that would predefine things like:

  • line width
  • line spacing
  • operator spacing
  • variable definitions + keywords e.g. integer, dimension(:) :: val vs integer :: val(:)

If yes, what would you like to see included in a formatting style?

I don’t think that the formatting styles should necessarily cover 100% of the Fortran syntax (at least at first) given that would be a major piece of work to produce.

13 Likes

I really like the idea.
Recently, I tried to follow the style guide @everythingfunctional posted two years ago (Free Style Guide).
Additionally, I try to add comments in a way FORD understands them.

Maybe it would be possible to collect all the things we need to cover (spacing, naming, etc.) first. And in the next step we could “vote” on default values for them, like indentation width etc.
Tools could then take these values and users of these tools shouldn’t need to change much, as the default values represent the average user.

3 Likes

I think it’s a worthwhile endeavor. I’d be more in favor of something like PEP8, but for Fortran. It’s also worth exploring what aspects of formatting Fortran code are there, as suggested by @Carltoffel.

4 Likes

Naming conventions for types and (maybe) modules would be good. Like a _t suffix for types and a _m or _mod suffix for modules.

Ideally a module name suffix shouldn’t be needed. I don’t think module names ever will clash with procedure or type names, but it seems like it’s still needed. Gfortran and ifort both reject this example, but I don’t see why it shouldn’t be allowed:

module foo
    implicit none

    private
    public foo

contains

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

program main
    use foo, only: foo

    call foo()
end program
2 Likes

I would be more than happy to have a black like formatter for Fortran and consistently apply it for all my projects, would remove one big headache when developing. My only concern for formatters is that they should be complete for all whitespace and diff friendly. Many clang format styles use hanging indents, which can case big diffs in case of name changes.

4 Likes

That would be great; something similar to the python PEP style formatting will help a lot in terms of code fast readability in the entire Fortran community.

2 Likes

A common problem that occurs in projects with several authors is that they all have their own preferences for trivial things like how much to indent do loops or how to align dummy argument lists. When one author applies his changes to a code and commits it to the repository, then all of those changes show up in the diff listings, swamping any of the actual changes that were made.

In fortran, this especially occurs with legacy fixed-format code. One of the first things I like to do with such code, even if it was originally written by me, is to convert to free format and indent do loops, if blocks, etc. Then someone else wants to compare my new version to the previous version, and he needs to look manually at every line of the code instead of just that single line where I fixed a sign mistake. This is more than just ignoring white space in the diff listings, it includes the change in continuation lines, declaring intent() for dummy arguments, replacing labeled continue with enddo, and so on.

One solution to this problem is to use an automatic formatting tool that is invoked whenever code is committed to the repository. Then any diffs that are displayed would eliminate many of the trivial changes to the text.

3 Likes

I agree. My original thinking was that we first need to create a style guide(s) (PEP8-like) and then enforce the style(s) with any of the following formatting tools:

  • a standalone formatter similar to black.
  • using LSP requests for textDocument/formatting.
  • using a compiler to run lint/format check. lfortran is currently capable of formatting, files and I expect its formatting capabilities will drastically improve in the near future.

@RonShepard the easiest way I can think automating this process would be with git hooks and pre-commit. That should be relatively easy to do and in theory we could create hooks now with the existing formatting tools that we have (findent and fprettify).


I would be more interested in having a discussion oh how that style guide should look like. What coding practices we should aim to promote and discourage. The idea being that we should pick styling features that are widely accepted and increase readability, rather than the personal taste of a single individual, which is how existing formatting tools are written.

4 Likes

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.