Modules

Overview

Teaching: 10 min
Exercises: 10 min
Questions
  • What are modules?

  • Why would I want to use a module?

  • Can I control what can be accessed from outside a module?

Objectives
  • Create a module.

Modules allow procedures (functions and subroutines) and variables to be grouped together as well as some other constructs we will talk about later.

A module is declared as shown below.

modules <module name>
  
  <variable declarations go here>
  
  contains
  
  <procedures go here>
  
end module

The contains keyword separates the variable declarations and the procedure implementations.

Modules are not strictly an object oriented only Fortran feature but are very handy to group together related object oriented constructs as we shall see.

Here is an example of a Fortran module.

module m_common
  implicit none
  
  integer:: value_one
  real:: value_two
  
  contains
  
  subroutine print_values()
    implicit none
    print *, "value_one=",value_one
    print *, "value_two=",value_two
  end subroutine
  
end module

program main
  use m_common
  implicit none
  
  value_one=1
  value_two=2
  call print_values()
end program

modules.f90

In the program main, to be able to accesses the variables and procedures defined in the module you must indicate you wish to be able to access them with the use keyword followed by the module name you would like your program or procedure to have access to.

By grouping related procedures and variables together into a module it can help to improve re-usability and allow modules to be used in multiple places in code.

Lets download, compile and run the above modules.f90 program.

$ wget https://raw.githubusercontent.com/acenet-arc/fortran_oop_as_a_second_language/gh-pages/code/modules.f90
$ gfortran modules.f90 -o modules
$ ./modules
 value_one=           1
 value_two=   2.00000000

Access Modifiers

It is possible to control how variables and procedures declared in a module are accessed from outside the module. This can be done either on module wide basis or for specific procedures and variables. If you specify no access modifiers everything will be accessible from outside the module. Access modifiers allows one to apply the OOP principle of encapsulation by restricting access to procedures and variables and keeping them internal.

It is often common in OOP style to have getter and setter procedures to access internal state. Some care should be taken to not get too carried away with this idea as it can lead to writing lots unnecessary code to access private members when they could have just been made public in the first place. Extra code would then require extra work when changes need to be made. However, there are also situations where it can be helpful to make members private that could be problematic if accessed from outside. Care always needs to be taken when applying OOP principles to ensure that they make sense rather than blindly applying those ideas in all situations.

There are two access modifiers:

Below is an example of using the private access modifier module wide.

module m_common
  implicit none
  
private
integer:: value_one real:: value_two contains subroutine print_values() ... end subroutine end module program main use m_common implicit none value_one=1 value_two=2 call print_values() end program

modules_access_none.f90

Add the private access modifier

Copy the modules.f90 file to modules_access_none.f90 and add the private access modifier to the m_common module, at the module wide level as shown above. Compile and run if you can. What is the result?

Solution

$ cp modules.f90 modules_access_none.f90
$ nano modules_access_none.f90

Then add the private access modifier, as shown above, and try to compile with the below command.

$ gfortran modules_access_none.f90 -o modules_access_none

You will get the following errors:

modules_access_none.f90:22:11:

   22 |   value_one=1
      |           1
Error: Symbol ‘value_one’ at (1) has no IMPLICIT type
modules_access_none.f90:23:11:

   23 |   value_two=2
      |           1
Error: Symbol ‘value_two’ at (1) has no IMPLICIT type

Indicating that the variables value_one and value_two can not be accessed from outside the module.

With the private access modifier variables declared in the module can’t be accessed from outside the module.

Stop using module variables outside the module

If the lines which reference to value_one and value_two are commented out and we try to compile again what happens?

Solution

$ nano modules_access_none.f90
...

program main
  use m_common
  implicit none
  
  !value_one=1
  !value_two=2
  call print_values()
end program
$ gfortran modules_access_none.f90 -o modules_access_none

then I get an error during the linking process like so:

/usr/bin/ld: /tmp/cc5TwvXi.o: in function `MAIN__':
modules_access_none.f90:(.text+0x118): undefined reference to `print_values_'
collect2: error: ld returned 1 exit status

Indicating that the subroutine print_values can not be accessed either.

As mentioned, individual variables and procedures can be selectively made either private or public.

module m_common
  implicit none
  private
  
  integer:: value_one
  real:: value_two
  
  
public:: print_values
contains subroutine print_values() ... end subroutine end module program main use m_common implicit none !value_one=1 !value_two=2 call print_values() end program

modules_access_some.f90

This version will compile and run and will print out the values of the two private variables of the module, however they won’t have been initialized to anything.

Using access modifiers allows certain data and procedures to be inaccessible from the user of these modules. Restricting access to data and procedures is a common practise in object oriented design.

Key Points

  • Modules are used to package variables, types, and procedures together.

  • Access to variables and procedures within the module can be controlled with the private and public access modifiers.