wingosoft

Fortran 90 introduced a data structure called modules that made a number of modern programming constructs easier to implement. Modules allow the user to easily incorporate funcionality from a package of routines into a new program. Modules also allow for better type-checking (i.e., it is easier to determine if you are calling the right subroutines with the right arguments). This brief tutorial will show you how to convert an old program over to the module format.

Consider the following definitions. Imagine they are part of a large project and exist in separate files.

subroutine swap(a, b)
       implicit none
       real, intent(inout) :: a, b
       real :: c
       
       c = a
       a = b
       b = c
end subroutine swap
program main
       implicit none
       real :: a, b
       
       a = 3.
       b = 7.
       write(*,'(2(A,f3.1," "))')"a: ",a,"b: ",b
       call swap(a,b)
       write(*,'(2(A,f3.1," "))')"a: ",a,"b: ",b
end program main

Note the use of a couple of new Fortran 90 constructs, intent(inout) and ::, the declaration delimiter. The first explicitly says that a and b will be modified within the procedure (function or subroutine) and applies only to dummy arguments. The second is an easy, clean way to declare a number of variables. You will see me use this exclusively. Also, note the use of the implicit statement, disallowing implicit variable declaration. It is practically impossible to write readable code (and impossible to do anything interesting) without this safeguard.

There is one minor issue with this arrangement: If you call swap with more than the requisite 2 variables, you will not receive any errors, not even when the compiler goes through the linkage stage. To prevent that from occuring, you can be paranoid and add an interface block to the main program:

program main
       implicit none
       real :: a, b
       
       interface swap
          subroutine swap(a,b)
	         real, intent(inout) :: a,b
          end subroutine swap
       end interface
       
       a = 3.
       b = 7.
       write(*,'(2(A,f3.1," "))')"a: ",a,"b: ",b
       call swap(a,b)
       write(*,'(2(A,f3.1," "))')"a: ",a,"b: ",b
end program main

But that's a bit excessive to do for every procedure that you call from every subprogram. Note that argument checking is in effect if the subroutine is declared in the same file as the program. Another issue with this arrangement is that your namespace gets polluted by all of the subroutines that get linked with your program.

Enter the module. By encapsulating subroutines in modules, somehow the compiler gets much sharper and can help you identify your errors in the compile stage. To rewrite this simple example in module form:

module sub
       implicit none

contains

       subroutine swap(a, b)
              real, intent(inout) :: a, b
              real :: c
              
              c = a
              a = b
              b = c
       end subroutine swap
end module sub
program main
       use sub
       implicit none
       real :: a, b
       
       a = 3.
       b = 7.
       write(*,'(2(A,f3.1," "))')"a: ",a,"b: ",b
       call swap(a,b)
       write(*,'(2(A,f3.1," "))')"a: ",a,"b: ",b
end program main

There are a couple of nifty things in the new module. First of all, by saying implicit none at the beginning of the module, you don't have to say it at the beginning of the subroutines. This is nice. Modules can also hold data, declared, as in a program block, before the contains statement. Modules, unlike program blocks, cannot have code that is not contained within a procedure. The contains statement is required. In this case, if you try to call the swap subroutine with more than 2 arguments, the compiler alerts you to your error.

This might seem like nitpicking, but there are several important advantages to this approach.

In conclusion, approaching a projects with modules in mind is not any more difficult than the old method and offers a number of advantages. If compatibility with old systems is still a goal, perhaps modules will not serve you very well, but for new programs it can prove quite useful.