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