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.
You have already been introduced to Modules in the earlier part of the workshop, but since they are very important for OOP design we will review them quickly.
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:
privateindicates that the procedure or variable can only be accessed within the modulepublicindicates 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
privateaccess modifierCopy the
modules.f90file tomodules_access_none.f90and add theprivateaccess modifier to them_commonmodule, 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.f90Then add the
privateaccess modifier, as shown above, and try to compile with the below command.$ gfortran modules_access_none.f90 -o modules_access_noneYou 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 typeIndicating that the variables
value_oneandvalue_twocan 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_oneandvalue_twoare 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_nonethen 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 statusIndicating that the subroutine
print_valuescan 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.