Netherlands eScience Center

We’re an independent foundation with 80+ passionate people working together in the Netherlands’ national centre for academic research software.

Follow publication

Writing non-questionable Fortran (Part 1)

--

Hello World! This is my very first blog about Fortran, I hope you enjoy the read!

Photo by Ugi K. on Unsplash

Fortran is a programming language that has been around since 1957, when measured in years, it is at least twice as old as me! It’s been the language of choice for many HPC applications, especially in the physics-related domains, but even as part of scipy! During its lifetime, standards for writing Fortran have changed. Even the format for writing Fortran has changed. Five standards of Fortran exist, listed from oldest to newest:

Fortran 77, Fortran 90, Fortran 95, Fortran 2008 and Fortran 2018

And two distinct formats for writing Fortran exist:

  • fixed form
    This is a legacy format which caps the line length, and interprets the first six characters differently (for line continuation characters and goto labels)
  • free form
    A modern format which does not have the line length limitation of fixed form and does not treat the first six characters differently.

It is important to note that all standards of Fortran can be written in any format, thus the fixed form format is not missing any functionality, it just can be annoying to format the code correctly. The two formats are usually separated by the file extension, .f for fixed form, and .f90 for non fixed format.

A broken Hello World

So you have decided you want to write some Fortran code? Great! Fortran still has its uses, especially in academia and research, and has some interesting properties for writing high performant code (e.g. subslicing of arrays and performance oriented aliasing assumptions). However, Fortran also has many pitfalls which are made worse by all the (scarcely known) legacy features that have to be supported.

And that brings us to the topic of this blog: How do you write sane, non-questionable Fortran nowadays?! For me the answer begins with making sure that no implicit behaviour is allowed by the compiler, meaning that the types of variables and signatures of procedures have to be specified explicitly by the programmer, and cannot be inferred by the compiler. Because Fortran does this in a very unintuitive way (for example, for variables it looks at the first letter of the variable to determine the type, what?! 😵), weird and hard to fix problems arise when implicit behaviour is allowed. Let’s look at the following example code that contains implicit behaviour:

gfortran has no problem compiling these files without warnings to create an executable, but when we compile and run this executable the output is not what we expect:

(We were expecting Hello World: You there right?)

Finding the Problem

What happens here is that Fortran can implicitly decide what functions and variables look like. In this example, this goes wrong in two places:

  1. The type of name is not specified in hello_world.f90. Therefore, Fortran looks at the first letter of the variable (in this case n) and decides that therefore it implicitly has to be an integer, not at all what we wanted!
  2. The call to the hello_world procedure in main.f90 is implicit, which means that the compiler has no information about what the actual procedure looks like, and decides on the spot what it should look like. In this case it would decide that the procedure has the following signature:

Which is different from the actual signature of the hello_world procedure that we have compiled, in that procedure name has the type integer!

Luckily gfortran (I’ll stick to gfortran, although many commercial/non-open compilers have similar flags, but named differently) has compiler flags available that disallow such legacy behaviour. The following two compiler flags should solve the issues that we are having with the example.

  • -fimplicit-none
    Do not allow any implicitly defined variables (this is the same as putting implicit none in every subroutine/function (which I guarantee you will forget at some point, and then this flag will save you)
  • -Werror=implicit-interface
    Do not allow any implicitly defined function calls

If we add implicit none to our program and procedures, and compile with the flags enabled the following happens:

Great! The compiler is trying to tell us what went wrong. Let’s solve the first error first. We have called the Procedure hello_world with an implicit interface, uh-oh 😨.

Fixing the Call to hello_world

The interface of the hello_world function can be exposed to the main.f90 in three ways:

  1. Including the hello_world.f90 file in the main.f90 file

2. Telling the compiler explicitly what the interface looks like and adding it to the program

3. Creating a module from the hello_world.f90 file, and telling main.f90 to use the hello_world definition from there

Method 1 causes the subroutine to be duplicated each time it is included, probably not ideal. Method 2 gets rid of the errors, but the interface is still not correct! Method 3 does not cause code duplication, and is not able to wrongly specify the interface. Therefore my preference always goes to method 3. However, now we have introduced an ordering in which the files must be compiled. There are a few programs out in the wild which can create the correct compile order for you (e.g. CMake and makedepf90 ). But for now we know the correct order, first we have to compile hello_world.f90 to get the interface hello_world_mod.mod and object file hello_world.o:

Aw shucks, we still have one more error left! gfortran tells us that we are trying to use a CHARACTER(1) in a function that takes an INTEGER(4). Which brings us to the second problem we have to solve: the types used in our program!

Recompile everything, et voilà:

We have successfully fixed our program and made all the interfaces and variables explicit, leaving less room for questionable-Fortran behaviour. Without implicit typing the code also becomes better maintainable and has better readability than before, which in turn means more people will be able to understand and use the code, win-win!

Takeaway

Always use the -fimplicit-none and -Werror=implicit-interface compiler options when compiling your Fortran code, and add implicit none to every procedure and the program itself!

Originally published at https://blog.lipsum.eu.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Published in Netherlands eScience Center

We’re an independent foundation with 80+ passionate people working together in the Netherlands’ national centre for academic research software.

No responses yet

Write a response