Fortran: Programs and modules
Matthias Noback
We have a basic Fortran application and a working environment to edit, compile and run it, thanks to FPM, IFX and Visual Studio Code. Let’s take a look at the structure of our very basic application.
The program
keyword
The minimum amount of code for a Fortran executable is this:
program the_program
! Do something here
end program the_program
Comment lines start with
!
. To write a multi-line comment, just repeat!
at the beginning of every line.
The program
keyword is similar to the main()
function in some other languages; it’s the entrypoint of the application. You don’t automatically get any command-line arguments though, and you can’t return an integer
value to be used as the exit code of the application (as you may be used to). You can just start doing your business, e.g.
program hello_world
print *, 'Hello, world!'
end program hello_world
The start and end of a program are indicated by the same name (e.g.
hello_world
). This isn’t mandatory, but it’s a best practice. Because we don’t have the possibility to use curly braces ({
and}
) and there’s no requirement for a consistent indentation, it’s helpful if you can visually match the end and beginning of a program. The same goes for modules, functions, etc.
In an FPM project it’s easy to create multiple executables. Every .f90
file in app/
will result in a single executable. The name of the executable will be the name of the file, not the name provided after program
.
The module
keyword
As we saw in the previous post, a minimal FPM project demonstrates the use of modules. They are a place to store your functions, similar to namespaces in other languages. When running fpm new
, FPM creates an example module, which defines a public
say_hello
subroutine (i.e. a function without a return value):
module hello_world
implicit none
private
public :: say_hello
contains
subroutine say_hello
print *, "Hello, hello_world!"
end subroutine say_hello
end module hello_world
In the module definition,
implicit none
means that the compiler should not assume that variables starting with the letteri
ton
are aninteger
value. That is, we want to explicitly declare each variable. If we forget to do it, we’d like to get a compiler error.Also note that the default visibility for functions etc. in this module is
private
, which is a best practice. Anything you want to let other modules and programs use, should be explicitly marked aspublic
.
The example program imports the say_hello
subroutine from the hello_world
module and calls it:
program main
use hello_world, only: say_hello
implicit none
call say_hello()
end program main
Importing is done with the use
statement. It’s a best practice to indicate what you want to import. If you don’t, all public
things from the module will be imported. This may sound convenient, but it makes it hard to find out which module actually declares the function that is used. It’s also hard to determine if an import is even needed.
Note: if a module imports for instance a
public
function from another module, that module can now expose this function as its own, and other modules can import it. This is a confusing practice, and you shouldn’t allow it, but it may be used in Fortran legacy code. It’s another important reason to make everything in a moduleprivate
: your module won’t accidentally expose another module’s function.
This post is part of a series that helps you get started with Fortran if you already have some experience programming in another language. The series isn’t supposed to be a full introduction to Fortran. I only want to show the basics, after which you’ll know everything to dive into more advanced Fortran features that allow you to do Object-Oriented or Functional Programming with it (or a mix of both!). In future posts we’ll also explore strategies for keeping Fortran programs maintainable.