Modules again
Last updated on 2026-07-10 | Edit this page
Overview
Questions
- How to organise large Fortran programs?
- How to minimise recompilation in large Fortran programs?
Objectives
- Understand how to separate modules into modules and submodules
- Understand the difference between
hostanduseassociation
Modules
The introductory course encouraged the use of modules to provide structure, and to separate public interface from private implementation. Schematically, we have seen:
module schematic
! Broadly, public "interface"
contains
! Broadly, private "implementation"
end module schematic
However, …
We also have a situation in which the (public) interface can remain unchanged, while a change to the (private) implementation requires recompilation of the module. This may have knock-on effects requiring re-compilation of any dependencies. Is this really necessary if we have not changed the interface?
The answer should be no. However, a typical makefile dependency might
cause re-compilation of all units use-ing the module
schematic. Some (rather baroque) mechanisms have been used
to avoid this, e.g., making a copy of the .mod file, and
interrogating whether this changes on compilation.
The separation of large modules into parts may be desirable, but can
necessitate the proliferation of public entities which might not really
be wanted. Cross-dependencies can also be a problem (the situation where
module a wants to use module b and
vice-versa).
Separate interface and implementation
This is not quite satisfactory. A clearer separation between interface and implementation (cf. C header files) is required.
Submodules
Submodules may be organised in a tree-like hierarchy, with the ancestor module as the root.
module example_module
end module example_module
The module should define only the interface (there should probably be
no contains statement).
The implementation can then be placed in a submodule:
submodule (example_module) example_submodule
contains
end submodule example_submodule
Host association
The submodule automatically has access to the declarations in the
example module via host association. There is no need to
use the ancestor module.
Formally, we have:
submodule (parent-identifier) submodule-name
[ specification part ]
[ module-subprogram-part]
end [submodule [ submodule-name] ]
where the parent-identifier is the name of the parent
module.
Submodule procedures
Suppose in our module we define a new data type:
type, public :: example_t
...
end type example_t
We can define an interface block using this type (also in the module) to specify the contract:
interface example_t
module function example_int_t(ival) result(e)
integer, intent(in) :: ival
type (example_t) :: e
end function example_int_t
end interface example_t
Note the module at the start of the
function declaration, and that there is no
import statement required in the interface block.
This would then be implemented in the submodule
subprogram part:
module function example_int_t(ival) result(e)
integer, intent(in) :: ival
type (example_t) :: e
...
end function example_t
Matching text
The interface and the function declaration must match precisely (only the name of the result variable is not formally part of the interface and need not match).
Exercise (2 minutes)
Compiling modules and submodules
Compile (do not link) the module and submodule files
example.f90 and example_a.f90 in the current
directory. E.g.,
$ ftn -c example_module.f90
$ ftn -c example_submodule.f90
Check what additional files have been generated (the exact details
will depend on the compiler: some produce .smod files,
others just additional .mod files).
Abbreviated form
It’s possible to omit the interface details in the submodule. E.g.,
module procedure example_t
...
end procedure example_t
Note the use of procedure here. Again, the details must
match the interface declared in the module.
A matter of taste
While this provides some saving in verbosity, it may be preferable to keep the full form.
Host association and use association
A submodule has access to entities in the parent module automatically
by host association, but may also use other modules in the
standard way.
Breaking circular dependencies
A submodule of module a can access module b
by use association. In addition, a submodule of
module b can access module a. This breaks the
circular dependency problem in standard modules.
Submodule declarations
Note that submodules do not contain public or
private declarations. However, additional variables, types,
or named constants may be defined in a submodule specification part.
These are neither public nor private, but can only be accessed in the
submodule and any descendants by host association.
Exercise (15 minutes)
Splitting a module into submodules
We will take the single module developed for the
file_writer_t and split it into a module containing the
abstract definition, and one or two implementations. A client program
should then only depend on the top-level (abstract) interface.
It’s probably easiest to make a number of copies of a working solution module, and then delete unwanted parts from each. Suggested procedure:
- Keep the abstract type
file_writer_tdefinition and its related interface block infile_module.f90. Here we will also need an interface for thefile_writer_from_string()function. Check the newfile_module.f90compiles on its own. - Make a new (ordinary) module
file_unformattedfor the unformatted implementation in a separate file, and a new modulefile_formattedfor the formatted implementation. - Add a submodule to
file_moduleto hold the implementation of thefile_writer_from_string()function in a separate file.
An example program which only has use file_module will
now depend only on the public definition of the abstract type.
All the Fortran sources should be compiled together to produce an executable.
What further decomposition into submodules could we make at this point?
- Submodules provide the mechanism to separate interface and implementation in Fortran
Comment on the use of submodules
Submodules may only really come into their own if you have an extremely large software project for which the overheads of re-compilation are high, or the organisation of extremely large single modules becomes a problem. For small exercises, such as those presented in this course, the additional files involved are probably an unnecessary distraction. So we will only use them on one occasion.