• No results found

Packaging Conventions

In document Fortran (Page 192-199)

9.1 Files

120. Place each program unit in a separate file.

Program units in Fortran are the main program, external subroutines, modules, and submodules. Placing each unit in a separate file makes the program easier to maintain. Shorter files tend to compile faster. You can locate different program components in files more easily. When a team of programmers is collaborating on a project, smaller files make it less likely that the work of one programmer will conflict with that of others.

It is crucial that you place submodules in files separate from their parent mod-ules. Doing so prevents “compilation cascade,” a phenomena where a change in the implementation of a subprogram needlessly causes the recompilation of other program units (see Rule 124).

121. Whenever possible, use the module name, the type name, the subpro-gram name, or the prosubpro-gram name as the file name.

This rule makes it easier to maintain programs. This is especially true if you code in conformance to Rule 133 and place each derived type in its own module, and you also choose to use either a prefix or suffix attached to a common base name when naming derived types and the modules that contain them. In that case, name the file according to the base name. For instance, you might have a type called pixel t defined in modulepixel mod, and you can name the file pixel.f03 (see Section 4.2).

9.2 External Procedures

External procedures are those that do not reside in a module or are an internal procedure within a main program. An explicit interface is not defined unless one is created by using interface blocks. Examples of external procedures are older FORTRAN 77 code, and code written in other languages, such as C.

122. Group the interface blocks for all user-defined external procedures in one or more modules. Use these modules in all procedures where these external procedures are referenced.

Using this rule allows an interface to be easily changed. Say you have an external subroutine contained in its own file:

165

s u b r o u t i n e S u b a ( a r g i , a r g r ) i m p l i c i t none

i n t e g e r , i n t e n t ( i n ) : : a r g i r e a l , i n t e n t ( i n out ) : : a r g r

. . . c o d e t o c a l c u l a t e a r g r end s u b r o u t i n e S u b a

In every location in the program from which Sub ais called, be it from a module subprogram or from another external procedure, an interface should be provided. One method of doing so is to include an interface block in the specification section of the calling unit.

s u b r o u t i n e S u b b i m p l i c i t none i n t e g e r : : i n t 1 r e a l : : r e a l 1 i n t e r f a c e

s u b r o u t i n e S u b a ( a r g i , a r g r ) i n t e g e r , i n t e n t ( i n ) : : a r g i r e a l , i n t e n t ( i n out ) : : a r g r end s u b r o u t i n e S u b a

end i n t e r f a c e . . .

c a l l S u b a ( i n t 1 , r e a l 1 ) . . .

end s u b r o u t i n e S u b b

If the interface changes, all such interface blocks must be changed accordingly.

A better method is to gather all such interface blocks into modules and use the modules where needed. The module would appear as shown in the following code. This method is the preferred manner in which to package a library of external procedures. The source code is placed in one or more files, and a module containing the interfaces to all the procedures is provided.

module I n t e r f a c e m o d i m p l i c i t none i n t e r f a c e

s u b r o u t i n e S u b a ( a r g i , a r g r ) i n t e g e r , i n t e n t ( i n ) : : a r g i r e a l , i n t e n t ( i n out ) : : a r g r end s u b r o u t i n e S u b a

. . . a d d i t i o n a l b l o c k s f o r o t h e r p r o c e d u r e s end i n t e r f a c e

end module I n t e r f a c e m o d s u b r o u t i n e S u b b

i m p l i c i t none i n t e g e r : : i n t 1

r e a l : : r e a l 1 use I n t e r f a c e m o d

. . .

c a l l S u b a ( i n t 1 , r e a l 1 ) . . .

end s u b r o u t i n e S u b b

123. Place the declaration of the dummy arguments of external procedures in a separate file and then include it using an include line in the file containing the procedure and every file containing its interface block.

Conforming to this rule will prevent you from inadvertently forgetting to change the interface block to an external procedure after you have modified the interface to the procedure itself.

Here’s an external procedure, contained in its own file, sub a args.f90, followed by the contents of the included file:

s u b r o u t i n e S u b a ( a r g 1 , a r g 2 ) i m p l i c i t none

i n c l u d e ” s u b a a r g s . f 9 0 ” . . .

end s u b r o u t i n e S u b a

! c o n t e n t s o f f i l e s u b a a r g s . f 9 0 complex , i n t e n t ( i n out ) : : a r g 1 r e a l , i n t e n t ( i n ) , o p t i o n a l : : a r g 2

The module making the interface available would look like this:

module I n t e r f a c e m o d i m p l i c i t none i n t e r f a c e

s u b r o u t i n e S u b a ( a r g 1 , a r g 2 ) i n c l u d e ” s u b a a r g s . f 9 0 ” end s u b r o u t i n e S u b a

. . . a d d i t i o n a l b l o c k s f o r o t h e r p r o c e d u r e s end i n t e r f a c e

end module I n t e r f a c e m o d

9.3 Submodules

Modules are the fundamental feature of modern Fortran for grouping highly related definitions, globally available variables, and procedures. However, prob-lems occur in large applications because there is not a clean split between the interface the module defines for the outside world, and the internal imple-mentation of that interface.

One problem is that of “compilation cascade,” whereby changes in a low-level module that did not affect the interfaces to its procedures trigger an unnecessary

recompilation of many program units that depend on that module’s interface.

The change could be as small as fixing a typographical error in a comment line, yet massive recompilation could occur.

A second problem is that it is sometimes desirable to distribute the interface in source form, yet maintain the actual procedural code separately as exter-nal procedures. In this case, interface blocks are defined for the procedures.

The problem here is that there is no linkage between the interface blocks and the actual procedures. The interface is therefore defined in at least two places. The developers must vigilantly keep multiple files in sync, or possibly useincludefiles in some manner (see Section 9.2).

The ISO/IEC Technical Report TR 19767, Enhanced Module Facilities (see Reference [32]) addressed the issue by developing “submodules.” This TR is incorporated as part of Fortran 2008. Submodules provide a method for cleanly separating the interfaces of module procedures from their implementation.

124. Use submodules to separate the interfaces of module procedures from their implementations. Specify the interface in the parent module only.

Here is a module that defines a data type vector t, and an interface block to define a function for that type: It is followed by a submodule that contains the actual implementation of the functionComp components:

module V e c t o r m o d i m p l i c i t none p r i v a t e

p u b l i c : : Comp components , UNIT VECTORS , v e c t o r t type , p u b l i c : : v e c t o r t

r e a l , d i m e n s i o n ( 3 ) : : o r i g i n = 0 . 0 , &

d i r c o s = [ 1 . 0 , 0 . 0 , 0 . 0 ] , v e c l e n = 0 . 0 end t y p e v e c t o r t

i n t e r f a c e

f u n c t i o n Comp components ( t h i s ) r e s u l t ( r e t v a l s ) i m p o r t : : v e c t o r t

i m p l i c i t none

t y p e ( v e c t o r t ) , i n t e n t ( i n ) : : t h i s r e a l : : r e t v a l s ( 3 )

end f u n c t i o n Comp components end i n t e r f a c e

t y p e ( v e c t o r t ) , parameter , d i m e n s i o n ( 3 ) : : &

UNIT VECTORS = &

[ v e c t o r t ( v e c l e n = 1 . 0 ) , &

v e c t o r t ( d i r c o s = [ 0 . 0 , 1 . 0 , 0 . 0 ] , v e c l e n = 1 . 0 ) , &

v e c t o r t ( d i r c o s = [ 0 . 0 , 0 . 0 , 1 . 0 ] , v e c l e n = 1 . 0 ) ] end module V e c t o r m o d

submodule ( V e c t o r m o d ) V e c t o r s u b m o d i m p l i c i t none

c o n t a i n s

module p r o c e d u r e Comp components

r e t v a l s = t h i s%v e c l e n * t h i s%d i r c o s end p r o c e d u r e Comp components

end submodule V e c t o r s u b m o d

Thesubmodulestatement specifies the module that the submodule is associated with. Here it is moduleVector mod.Themodule procedurestatement states that the interface from the parent module is to be used. In this case, it is function Comp components. The argument list and various declarations do not need to be repeated, so there is no opportunity for error. The submodule code for this can, and, in fact, should, reside in a separate file from the parent module, so that it can be developed independently of the interface.

A drawback of this manner of writing the procedure code in submodules is that you do not see the interface when you are looking at the source code listing;

you need to refer to the listing of the parent module as well. The submodule that follows, however, would also work. Its use removes this disadvantage by repeating the interface. The compiler is required to compare the two interfaces and issue an error if they differ. However, the previous form is still preferable because the code specifying the interface exists solely in one place, the parent module. If you need to change the interface, you can make all changes to the interface code in it alone.

submodule ( V e c t o r m o d ) V e c t o r s u b m o d c o n t a i n s

f u n c t i o n Comp components ( t h i s ) r e s u l t ( r e t v a l s ) t y p e ( v e c t o r t ) , i n t e n t ( i n ) : : t h i s

r e a l : : r e t v a l s ( 3 )

r e t v a l s = t h i s%v e c l e n * t h i s%d i r c o s end f u n c t i o n Comp components

end submodule V e c t o r s u b m o d

The parent module is the one specified in usestatements in other program units to obtain access both to the module procedure interfaces and to objects whose scope is the module.

module ModA mod

use Vector mod , o n l y : Comp components , v e c t o r t i m p l i c i t none

p r i v a t e

p u b l i c : : ! . . . l i s t o f p u b l i c e n t i t i e s

c o n t a i n s

! . . . p r o c e d u r e s t h a t r e f e r e n c e t h e f u n c t i o n

! . . . Comp Components i n s u b m o d u l e V e c t o r s u b m o d . end module ModA mod

If you modify the implementation of Comp components in submodule Vector submod, but do not modify the interface, module ModA modneed not be recompiled because it does not useVector submod.

When using an application building tool, such as make, in the specification used to build the application, compilation of the parent module is the prereq-uisite for compilation of the submodules. It should also be the prereqprereq-uisite for all program units that need access to the public entities and interfaces of the module; compilation of the submodules should not be the prerequisite to these units. For this reason, you should define all public objects, not just the inter-faces, in the parent module. The named constantUNIT VECTORSin module Vector modin the previous example is an example as is the type vector t. With most make programs, you will need to place the parent module and each of its submodules in a separate file to prevent the unneeded compilation (see Rule 120).

10.

In document Fortran (Page 192-199)