Modules
Overview
Teaching: 10 min
Exercises: 10 minQuestions
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
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:
private
indicates that the procedure or variable can only be accessed within the modulepublic
indicates it can be accessed from outside the module.
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
Add the
private
access modifierCopy the
modules.f90
file tomodules_access_none.f90
and add theprivate
access modifier to them_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
andvalue_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
andvalue_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
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.