.. _ch02-fortran-modules: ============================================================= Fortran modules ============================================================= Modules provide a way to package together groups of functions, subroutines, and data that all serve some common purpose. Splitting your code into well thought out modules is probably the most useful thing you can do for readability and maintainability. Modules can also import the contents of other modules. This allows more complex functionality to be methodically built up from more fundamental pieces. The general structure of a Fortran module .. code-block:: fortran module ! Import any other modules ! Declare variables contains ! Define subroutines or functions end module A program or subroutine can ``use`` this module like so: .. code-block:: fortran program use ! Declare program variables ! Execute statements, call the module, etc. end program It is useful to make your module imports more explicit. The ``use`` statement can be replaced by .. code-block:: fortran use , only: to specify that only certain variables/subroutines/functions from the module should be used. Doing it this way also makes it clear exactly what symbols are coming from which module in the case where you *use* several modules. A very simple module is: .. literalinclude:: ./codes/sub1m.f90 :language: fortran :linenos: :download:`Download this code <./codes/sub1m.f90>` and a program that uses it is: .. literalinclude:: ./codes/main.f90 :language: fortran :linenos: :download:`Download this code <./codes/main.f90>` These source files can be compiled as: .. code-block:: console gfortran -c sub1m.f90 gfortran -c main.f90 gfortran -o modules.ex main.o sub1m.o Some reasons to use modules ----------------------------- * Can avoid global variables by putting shared resources into a module, and having multiple portions of the code reference that module. In Fortran 77 this had to be done with common blocks -- much less elegant. * Subroutine/function interface information is generated to aid in checking that proper arguments are passed. It's often best to put all subroutines and functions in modules for this reason. * Can define new data types to be used in several routines. Compiling modules ------------------- Modules must be compiled *before* any program units that *use* the module. When a module is compiled, a ``.o`` file is created, but also a ``.mod`` file is created that must be present in order to compile a unit that *uses* the module. This ``.mod`` file contains, among other information, the generated interface information. Circles module example ------------------------ Here is an example of a module that defines one parameter ``pi`` and two functions: .. literalinclude:: ./codes/circle1/circle_mod.f90 :language: fortran :linenos: :download:`Download this code <./codes/circle1/circle_mod.f90>` This might be used as follows: .. literalinclude:: ./codes/circle1/circle_main.f90 :language: fortran :linenos: :download:`Download this code <./codes/circle1/circle_main.f90>` To compile, you first need to generate ``circle_mod.o`` and ``circle_mod.mod``, followed by ``circle_main.o``. Only then, you can link the two object files together to produce a binary (or an executable) file, e.g., ``circle.ex`` .. code-block:: console $ gfortran -c circle_mod.f90 # produces circle_mod.o and circle_mod.mod $ gfortran -c circle_main.f90 # produces circle_main.o $ gfortran -o circle.ex circle_main.o circle_mod.o # linking to generate circle_main.ex If you reverse the order of the compilations between ``circle_mod.f90`` and ``circle_main.f90`` in the above it won't compile and fail with an error message such as .. code-block:: console circle_main.f90:5.6: use circle_mod, only: pi, area 1 Fatal Error: Can't open module file 'circle_mod.mod' for reading at (1): No such file or directory Executing the program by running ``./circle.ex`` after a successful compilation gives the following output .. code-block:: console pi = 3.14159265358979 area for a circle of radius 2: 12.5663706143592 Note that a parameter defined with a specific value in a module (e.g., ``pi`` as defined in ``circle_mod.f90``) is available to all program units using the module (e.g., ``pi`` is accessible from ``circle_main.f90`` via ``use circle_mod, only: pi``). See :ref:`module_variables`. .. note:: You can now see that compiling :math:`N` source files via using :math:`N` calls to ``gfortran`` will be very tedious, especially when :math:`N` is large. In this case compiling with a ``Makefile`` becomes very handy (see :ref:`ch02-fortran-makefiles`). .. _module_variables: Module variables and parameters --------------------------------- It is also possible to declare *variables* within a module that can be shared between all program units using the module. This alone is essentially the same as using global variables, which we would like to avoid. We'll see shortly how to avoid the shortcomings of this style, and ultimately find module variables to be extremely useful. Module variables can also be directly referenced by any subroutines and functions defined in that module without needing to pass them as arguments. This substantially cleans up the code. If you want the value of a variable to persist between references to it you can use the ``save`` keyword. For example: .. code-block:: fortran real (kind=8), save :: pi is used to indicate that the variable ``pi`` defined in the module should have its value saved for use by any program unit with access to the module. This is a better way to manage shared resources than using global variables. However, care must be taken to avoid letting these saved module variables become global variables in disguise. **Remark** Care should be taken when using this idea, as a strong reliance on saved variables stored within (other) modules can make code harder to read, understand, and debug. They still have a purpose though. I would advise using ``save`` to store state `internal` to the module, and avoid using those variables directly when outside the module. A common use case for this is when a module needs to perform some memory allocation internally. **Remark** Placing related constants together into a module is an excellent use case for module variables. In this case each will be declared with ``parameter`` and set at the declaration site. Consult the module in ``utility.f90`` from :ref:`ch02-fortran-mathieu`. Here is another version of the circles code that stores ``pi`` as a module variable rather than a parameter: .. literalinclude:: ./codes/circle2/circle_mod2.f90 :language: fortran :linenos: :download:`Download this code <./codes/circle2/circle_mod2.f90>` In this case we also need to initialize the variable *pi* by means of a subroutine. Note the new ``initialize`` subroutine defined in this version of the module. These might be used as follows in a main program: .. literalinclude:: ./codes/circle2/circle_main2.f90 :language: fortran :linenos: :download:`Download this code <./codes/circle2/circle_main2.f90>` This example can be compiled and executed by typing .. code-block:: console $ gfortran circle_mod2.f90 circle_main2.f90 -o circle.ex $ ./circle.ex In the next section we are going to learn more about Makefiles. This will greatly simplify our lives and let us stop thinking about the compilation process all the time. The ``public`` and ``private`` keywords ----------------------------------------- By default all variables, subroutines, and functions defined in a module are accessible to any other module or program that can ``use`` it. We have already mentioned that using global variables can strongly limit the readability and maintainability of code, and by extension, make code very difficult to debug. To combat this issue we can mark certain variables, functions, or subroutines as ``private``. This means that they can only be referenced from within the module itself, and are inaccessible to any other users of the module. This means that we can design a few ``public`` subroutines and functions that interact with the internal structure of the module. This substantially improves readability because you know that all users are only modifying the internal state of your module through your public interface. We can go one step further and make all contents ``private`` by default, then the only ``public`` members will be the ones we explicitly specify. Consider another iteration of the circle module: .. literalinclude:: ./codes/circle3/circle_mod3.f90 :language: fortran :linenos: :download:`Download this code <./codes/circle3/circle_mod3.f90>` which could then be called from a main program like so: .. literalinclude:: ./codes/circle3/circle_main3.f90 :language: fortran :linenos: :download:`Download this code <./codes/circle3/circle_main3.f90>` As before, this example can be compiled and executed by typing .. code-block:: console $ gfortran circle_mod3.f90 circle_main3.f90 -o circle.ex $ ./circle.ex There are a few interesting things to note about this module and how we call it: * The ``private`` keyword on line 7 of the module sets all contents to default to private access * We need to explicitly mark subroutines and functions as ``public`` if we want users to have access to them - This example is a little artificial since we end up exporting all members - We'll see more complicated code soon that makes direct use of this pattern * The ``pi`` module variable is private so we can not use it in the main program - Try importing it on the ``use`` line and uncomment the print statement to see how this fails