300 likes | 314 Views
Learn about procedural refinement and program organization, including modularization, data hiding, and module subprograms. Understand the benefits of subdividing a program and the importance of accessibility control in modules.
E N D
Chapter 9 Modules and ProgrammingwithFunctions
Introduction • It is often appropriate to subdivide a computational task-especially large one- into subtasks that can be developed and analysed independently. The overall task may be organised as a set of procedures that implement the subtasks. Each procedure is defined by an independent group of statements called a subprogram. This process of subdivision is called procedural refinement. For instance, you can organise a data processing task with separate procedures for input, computation, and output. • The first step in procedural refinement is to plan what the main program will do and what information it should transmit to and from each procedure. Then, during the development of each of the separate procedures, you concentrate on its internal details and on its relation to the main program. If you subdivide a large task into a few relatively independent chunks and analyse each of the chunks without thinking too much about any of the others, you can keep the overall problem organization in mind surprisingly well.
Program organization • There are two principal reasons for subdividing a program: 1) Modularity; dividing a project into pieces so that each piece can be studied independently, with minimal concern for the other pieces or for how they fit together. Thus, a problem that is too complicated to be comprehended as a whole may become managable when it is subdivided into nearly independent parts. 2) Data hiding; protecting information in each part of the program from access, and especially from being changed, by other parts of the program. • A module is an independent group of statements that can be imported in whole or in part by the main program or by other modules. Especially important is accessibility control: each data object, procedure, or derived type is declared to be either public(so that it becomes accessible when the module is imported) or private (so that it remains inaccessible).
Main program and module subprograms • Every program must include exactly one main program and may also include one or more modules (see the following figure). • Structure of typical main program and module Main program Main procedure Module Specification part Module subprogram Module procedure Module subprogram Module procedure
Main program and module subprograms • A module can have a specification part, and it can have a subprogram part with one or more module subprograms. Either of these parts may be omitted. • A module subprogram is contained in a module; module subprograms cannot be nested inside each other • A module subprogram defines a procedure that can be referenced from the main program or from a module subprogram. • Most processors use a linker to combine the main program all required modules into an executable program. Intrinsic procedures are automatically supplied by the processor; no action is needed to make them available.
Main program and module subprograms • As you know the main program begins with a program statement that gives the program a name: program Program name ------ end programProgram name • Subroutine procedures and function procedures are defined by module subprograms. A function has result variable, named in the function header, whose value is returned to any expression where a reference to the function appears. • A reference to a subroutine appears in a callstatement. call Subroutine name (Actual argument list) call Swap(A, B) • If there are no arguments, an empty pair of parentheses follows the subroutine name: call Push()
Module subprograms • Procedure definitions for F are organized as module subprograms, in a module that is named in a use statement in the main program: -------------------------------------------------------------------------------------------- program Program name use Module name . . . end program Program name --------------------------------------------------------------------------------------------- module Module name . . . contains module subprograms . . . end module Module name ---------------------------------------------------------------------------------------------
Module subprograms • A module may contain more than one module subprograms. Several subprograms may appear within the module, following a containsstatement which declares that the following lines ( to the end of the module) contain module subprograms. The module is considered the host of its module subprograms. • The specification part of the module-the part that precedes the containsstatement- must include publicor privateaccessspecifications for all procedure names defined in module subprograms. • Normally, the main program will import the procedure names; accordingly they are declared with public accessibility. • There may also be private procedure names that are referenced only from other procedures within the module.
Defining a procedure • A procedure that has a result value is calledfunction. • A procedure that does not have a result value is calledsubroutine. • It is one of the restrictions of F that functions must be pure, which means that they cannot have side effects such as input or output, intent(out) dummy arguments, intent (in) dummy arguments, or assignment to variables declared at the module level. • In the function subprogram, the value to be returned by the function will be assigned to the result variable. A type declaration for the result variable appears inside the function subprogram; The declared type and other attributes also apply to the function reference expression in the main program. • The function result must be a single value, which may be a single (scalar) value or a composite(array, string, or derived-type structure) value; it may also have the pointerattribute (we will see in the following chapters).
Defining a procedure (Function) • A subprogram begins with a functionstatement that names the procedure and lists its dummy arguments. Since there is an implicit none statement in the host module, none is needed in a module subprogram; the requirement is “inherited” from the module. • A function statement has the following form: function heading specification part execution part end function part The function heading is a function statement of the forms: pure functionFunction name (Dummy Arg List) result (Result name) or function Function-name (Formal-argument-list) where the Function-name may be any legal Fortran identifier, Formal-argument-list is an identifier or a list of identifiers separated by commas Note:All F functions are pure. However, the keyword is not supported by early releases of F90 or F compilers.
Defining a procedure (Function) • The specification part of a function subprogram has the same form as the specification part of a Fortran program with the additional stipulation that it must declare 1) The type of the function value if this has not been included in the function heading. 2) The type of each formal argument. These declarations should also contain an intent specifier that tells how the arguments are to transfer information. • Similarly, execution part of a function subprogram has the same form as the execution part of a Fortran program with the additional stipulation that it should include at least one statement that assigns a value to the identifier that names the function. Normally, this is done with an assignment statement of the form function-name = expression • The last statement of a function subprogram must be end function function-name
Example (temperature conversion) • The formula for converting temperature measured in degrees Fahrenheit into degrees Celsius is C = (F -32) / 1.8 where F is the Fahrenheit temperature to be converted and C is the corresponding Celsius temperature. Suppose we wish to define a function that performs this conversion. Solution: A function subprogram to implement this formula is: function Fahr_to_Celsius (Temperature) this function returns a real value, its name must be declared to be of type real in the function’s specification part, real :: Fahr_to_Celsius or in the function’s heading: real function Fahr_to_Celsius(Temperature) Since the formal argument Temperature must be of typereal and will be used only to transfer information into the function, the specification part of this function subprogram must also contain the following declaration
Example (temperature conversion) real, intent(in) :: Temperature The complete function subprogram is: function Fahr_to_Celsius(Temperature) !Function heading real :: Fahr_to_Celsius !Specification part real, intent(in) :: Temperature Fahr_to_Celsius= (Temperature -32.0) / 1.8 !Execution part end function Fahr_to_Celsius !End function statement
Example(temperature conversion) • This function subprogram can be made accessible to a program, called the main program, in three ways: 1) It is placed in a subprogram section in the main program just before the end program statement; in this case it is called an internal subprogram. 2) It is placed in a module from which it can be imported into the program; in this case, it is called a module subprogram. 3) It is placed after the end program statement of the main program, in which case it is called an external subprogram.
Internal subprograms • Internal subprograms are placed in a subprogram section at the end of the main program (or at the end of an external subprogram). The program unit (main program or subprogram) that contains an internal subprogram is called a host for that subprogram. This subprogram section has the form contains subprogram1 subprogram2 . . . subprogramn where each subprogrami does not contain a subprogram section. • Following example illustrates the use of an internal subprogram.
Example for internal subprogram Program Temperature_Conversion_1 implicit none real :: FahrenheitTemp, CelsiusTemp character(1) :: Response do write (*, ‘(1X, A)’, advance = “no”) “Enter a Fahrenheit temperature: “ read *, FahrenheitTemp CelsiusTemp = Fahr_to_Celsius(FahrenheitTemp) print ‘(1X, 2(F6.2, A))’, FahrenheitTemp, “ in Fahrenheit is equivalent & to “, CelsiusTemp, “ in Celsius” write (*, ‘(/ 1X, A)’, advance = “no”) & “More temperature to convert (Y or N) ?” read *, Respond if (Respond /= “Y”) exit end do contains function Fahr_to_Celsius (Temperature)
Exercise for internal subprogram real :: Fahr_to_Celsius real, intent (in) :: Temperature Fahr_to_Celsius = (Temperature - 32.0) / 1.8 end function Fahr_to_Celsius end program Temperature_Conversion_1 IMPORTANT: Including the intent(in) attribute in a formal argument’s declaration protects the corresponding actual argument by ensuring that the value of the formal argument cannot be changed while the function is being executed. Any attempt to change the value of the formal argument will result in a compile-time error.
Self Study • Study pages between 68 - 80 (Ellis’s Book).
Modules • A module is a container for specifications and subprograms that can be “imported” into other programs or subprograms by means of a use statement. A module begins with a modulestatement that includes the module name and ends with an end modulestatement that repeats the name. A module has two-level structure: 1) The outer level consists of a specification part followed by a subprogram part. Either of these parts may be omitted. 2) The subprogram part, if present, consists of a contains statement followed by one or more module subprograms at the second level. Each module subprogram defines one module procedure. No further nesting beyond this level is permitted.
Two level module structure • Module Name • ------------------------------------------------------------------------ • . • . • . • ------------------------------------------------------------------------ • contains • ------------------------------------------------------------------------ • end module Name Specification part (optional) Module Subprogram Subprogram part (optional) Module Subprogram Module Subprogram
Specification part of module • Specification part of a module may include variable declarations, named constant declarations, and derived type definitions. Object declarations and type definitions in the specification part are accessible to all module subprograms in the same module. • Names of variables and constants declared in the specification part, derived types defined in the specification part, and module procedures must be given an Access specification, which is either public or private. • Accessspecifications are permitted only in the specification part of the module; local names in a module subprogram are not visible outside the subprogram, so they can not be declared public and they do not need to be declared private.
Specification part of module public :: Sub_1, Func_1 type, public :: A_New_Type . . . end type A_New_Type integer, parameter, private :: String_length=20 • Both public and private names are accessible from any subprogram in the same module. Names declared public are also accessible from the main program or from any other module, if it has a use statement referring to the module.
Using a module • Once a module has been written, its contents can be made available to any other program unit by placing in that program unit a use statement of the form useModule-name at the beginning of the specification part of a program unit. The use statement may also have the form use Module-name, only : List of names where List of names is a list of identifiers declared in that module and renamings of these identifiers of the form new-identifier => identifier In this form, only the identifiers listed are imported. These identifiers or their new names may then be used in the program unit containing this use statement.
Public names • A use statement imports all public objects (with their types and other attributes), public derived types and their components, and interface information for all public module procedures. • A declaration for public module procedures appears in the specification part of the module: public :: List • Type declarations for public variables and named constants include the keyword public as an attribute specifier. For example: integer, public, parameter :: S_length = 23 real, public :: Street_number = 1024 character (len =S_length), public :: Word =“Hello” • Definitions of public derived types include the keyword publicfollowing the keyword type on the first line of the definition: type, public :: List_item character (len = 20) :: Word integer :: Sequence, Count end type List_item
Public names • The internal structure of apublic derived type may be hidden by placing the keyword private alone on the second line of the type definition: type, public :: List_item private character (len = 20) :: Word integer :: Sequence, Count end type List_item • This latter feature is useful in a module that encapsulates a derived type along with a complete set of operations upon it. We will see the data encapsulation in the following chapter.
Private names • A private module-level data object (variable or named constant), derived type definition, or module procedure is not imported along with the module into the main program or another module. This feature contributes to data protection by “hiding” (and thus protecting) unneeded information from the user of a module. Objects and definitions that are private can be shared by procedures within the module, but are not visible outside the module. • A declaration for private module procedures appears in the specification part of the module: private :: List • Type declarations for private variables and named constants include the keyword private as an attribute specifier. For example: integer, private, parameter :: Password = 07734, S_length = 23 real, private :: Salary_of_Ceo = 1.0e6 character (len =S_length), private :: Secret_word =“Groucho”
Private names • Definitions of private derived types include the keyword privatefollowing the keyword type on the first line of the definition: type, private :: List_item character (len = 20) :: Word integer :: Sequence, Count end type List_item
Module linking • Translation of a source program to produce an executable program consists of two separate steps: 1) Compilation, in which the source program is translated to an equivalent machine-language program, called an object program, which is stored in an object file. (Unix object files have the extension .o, Dos object files have the extension .obj). 2) Linking, in which any references to functions contained in a module are linked to their definitions contained in a module are linked to their definitions in that module, creating an executable program, which is stored in an executable file. • Since modules also need to be compiled, translation of a program that uses a module may require three separate actions: 1) Separate compilation of the program’s source file, creating an object file 2) Separate compilation of the module, creating a different object file 3) Linking the function calls in the program’s object file to the function definitions in the module’s object file, creating an executable program
Module linking • It makes no difference whether the source program or the module is compiled first, but both source programs and modules must be compiled before linking can be performed. The following diagram illustrates this process: Fortran 90 Compiler Program source file Program object file Linker Program executable file Fortran 90 Compiler Module source file Module object file
Exercise • Read pages 80-98 (Ellis’s Book).