Module and Data Sharing

Programming in the Large

      Software, in general, is large having multiple units

      Multiple units designed and developed independently

      But these units executed together to achieve some common goal

      Units share data and need to communicate with one another

      Large software require mechanisms for designing and developing multiple units

      Flexible and powerful mechanism for Communication or sharing of data essential

Parameters and Global Variables

      Fortran provides two means of communication

      Parameters: Subroutines and main programs can share data via parameters

      Global Variables: Internal routines and functions can share the variable in the main program

      Both are restrictive

   Too many parameters

   All routines in the same file

      A more general mechanism desirable for programming in the large

      Modules is the Fortran Solution for this

Module definition

      Here is an example module definition

 

    module example

      implicit none
  save   ! guarantees saving all data values declared

  integer, parameter:: pi = 3.141592
  real:: x, y, z

  real, dimension(100,100):: satellite_data

end module example

Module use

Program using_example

use example   ! appears before all other statement
implicit none

integer:: i, j

do i = 1, 100
   do j = 1, 100
      satellite_data(i, j) = pi * i + j
   end do
end do

call test_routine

end program

Module use in procedures

subroutine test_routine

use example ! like in the program
implicit none

..
satellite_data(i, j) = ...

...

end subroutine

Data Sharing using modules

      Data declared in different modules can be shared among main program and subroutines and functions

      Variables can be assigned and updated by all the units

      Values are retained with SAVE attribute

      a simple and efficient mechanism for sharing large amount of data

      No need for passing large amount of data via parameters

      Modules can be separately compiled and linked later

Procedures can be shared too

   Module example1
      implicit none

      -- shared data ---
  
      contains
         subroutine ex1(x, y, z)
            implicit none
    
             -- parameter and local variable declarations

            -- body
         end subroutine

      -- other procedure or function definition

 end module example1

Using the procedures

       Main program and any procedure that uses the above module can call ex1 and other routines declared

       Advantage over conventional method

    increased safety

       Modules with procedures create (when compiled) EXPLICIT INTERFACES

       compile with -c option creates .vo file containing the interface

       Explicit interface for a procedure contains

            no. , type, intent of each argument

       When the calling program compiled, the compiler checks whether the calls match the interfaces and flag errors, if any

       When procedures not in a module compiled only an implicit interface is created

    No details about the procedures

    compiler can then miss errors leading to strange errors at run-time

High Level Data Types

      Another use of including procedures in modules is extensibility

      New data types can be created by the users

      Suppose we want to create a new data type Polynomails

    Data Values: all possible ploynomials of, say degree 4

    Operations:  Addition, Subtraction, multiplication                                 by a constant, creation, coefficient                                     extraction

      Modules useful for defining such a data type

Polynomial data type

Module polynomial
implicit none

type:: poly
  real:: x
  real:: y
  real:: z
  real:: w
end type

contains
  subroutine create(poly_result, x1, y1, z1, w1)
    implicit none
    type (poly), intent(out):: poly_result
    real:: x1, y1, z1, w1
    poly_result%x = x1
    poly_result%y = y1
    poly_result%z = z1
    poly_result%w = w1
  end subroutine

Polynomial Module continued

subroutine add(poly_result, poly1, poly2)
    implicit none
    type (poly), intent(out):: poly_result
    type (poly), intent(in):: poly1, poly2
    poly_result%x = poly1%x + poly2%x
    poly_result%y = poly1%y + poly2%y
    poly_result%z = poly1%z + poly2%z
    poly_result%w = poly1%w + poly2%w

end subroutine

 subroutine multiply(poly_result, poly1, a)
    implicit none
    type (poly), intent(out):: poly_result
    type (poly), intent(in):: poly1
    real, intent(in):: a
    poly_result%x = a* poly1%x
    poly_result%y = a* poly1%y
    poly_result%z = a* poly1%z
    poly_result%w = a* poly1%w

end subroutine

The main program

Program poly_main
use polynomial
implicit none

type(poly):: a, b, c, d, e
real:: a1, a2, a3, a4
real:: b1, b2, b3, b4

print *, "type the coefficients of a"
read *, a1, a2, a3, a4

print *, "type the coefficients of b"
read *, b1, b2, b3, b4

call create(a, a1, a2, a3, a4)
call create(b, b1, b2, b3, b4)

call add(c, a, b)
call multiply(d, a, a1)
call multiply(e, b, b1)

print *, c%x, c%y, c%z, c%w
print *, d%x, d%y, d%z, d%w

end program

A Problem

       Units using a module can access any entities declared in the module

       For example, the main program above accesses the x,y,z,w components to print the polynomial coefficients

       But this is undesirable

       Loss of Abstraction:

    Polynomial module provides an abstract data type of polynomails

    The operation like c%x is meaningless at the level of polynomials

    It is like accessing 5th bit of an integer variable

 

       Not robust under change of representation

    Structures are internal data structures to represent polynomials

    Suppose tomorrow we choose to use arrays for representing polynomials

    then the main program would not work

The solution

       There is a need for an abstract routine that returns any coefficient of a polynomial

       But that is not enough - main program can even then access the internal representation

       There is a need for a mechanism to restrict the access of module components

       Components can be declared to be public or private

       For example, the above problem disappears if we declare

        type:: poly
       private
       real:: x
       real:: y
       real:: z
       real:: w
    end type

       Then any reference to the components like c%x, d%z is illegal

       Separate routines needed for printing coefficients

Public and Private Components

      In general, any component, data or routines can be declared public or private

      The declarations are:

          private:: list of private items

          public:: list of public items

      A declaration  private inside a module (after implicit none)

    declares all items to be private

      Default: all items are public

      Alternate declarations is:

          integer, public:: x, y, z

          real, private:: a, b, c

Assumed Shape arrays

      Array parameters in procedures

    usually the shape of array is explicitly given

    Example:    real, dimension(n,m):: arr1

                    where n,m are also arguments

      If procedures are declared in a module then no need for specifying n, m

      They can be automatically found using intrinsic functions

    LBOUND(arr1,i): lower bound in ith dimesion

                                        (this will be 1)

    UBOUND(arr1,j): upper bound in the jth dimension

      Shape and size can be inferred using these functions in called program

      Actual bounds can not however be inferred

    use explicit shape array if required