Fortran-90/95/2003 permits functions or subroutines to call themselves recursively, a feature not implemented in earlier versions of Fortran. Recursive procedures will be dealt with separately in the next chapter (cf. Chapter 11).
SUBROUTINE name ( formal argument list ) . . . RETURN ENDNOTES:
a) RETURN is used in subroutines and functions instead of STOP. The RETURN signifies the logical end of the subprogram. As with the STOP, there may be more than one RETURN in a subroutine, although multiple RETURNs are marked as an "obsolescent" feature in Fortran-95 and should be avoided. As with the STOP statement, Fortran-90/95/2003 permits omitting the RETURN if it comes immediately before the END.To invoke a subroutine from the main program (or from any other subprogram), one uses the key word CALL, followed by the name of the subroutine, followed by actual arguments (separated by commas) enclosed in parentheses. For example,b) The formal argument list, enclosed in parentheses after the subroutine name, contains only the variable names (separated by commas). The types and array dimensions are declared internally within the subroutine.
c) All variables are local and should be (normally) declared explicitly within a subroutine, particularly when coding subroutines "externally" (see section 10.3.3). As noted in the previous chapter on modules (section 9.1), there are no global variables in Fortran (unless one makes use of modules). Therefore, in particular, arrays that are parameters must be explicitly re-declared. (Exceptions to this declaration rule occur when making use of the Fortran-90/95/2003 features of "internal" procedures (see section 10.3.1) or modules for declaring variables.)
d) All statement numbers (e.g., used in FORMAT statements) are also local, i.e., independent of numbers in the main program or any other subprogram.
e) In cases where the subprogram is totally self-contained, for example where it generates and/or prints information and neither receives nor gives information to the calling program, the argument list and the enclosing parentheses are omitted.
CALL name ( actual argument list )
The actual arguments used in the CALL statement and the formal (or "dummy") arguments used in the definition statement must match in number, order, and type. Switching the order of the arguments, neglecting to declare the data type of any variables used as arguments, or omitting arguments can lead to errors (exceptions to this principle are noted in Chapter 12). Sometimes the errors or inconsistencies may be caught by the compiler before execution, but at other times they are not, resulting in incorrect answers due to hard-to-detect causes.
The argument passing scheme used in Fortran is such that the values of the actual arguments will always be changed if the formal argument values are changed in the subprogram code. See section 10.7 below for more details.
NOTE: If the subroutine has no formal argument list (cf. Note e above), then there is no actual argument list (nor any parentheses) in the CALL statement.
Thus, as an example, one might have:
PROGRAM SAMPLE2
! main program code
STOP ! last main program statement
CONTAINS
SUBROUTINE ONE
! subprogram code
RETURN
END SUBROUTINE
SUBROUTINE TWO
! subprogram code
RETURN
END SUBROUTINE
END PROGRAM
In this approach, the procedures have complete access to all
variables and other entities declared in the main program (as an
exception to the older Fortran rule). Thus a variable declared
in the main program may be changed by an action in the subprogram
without the necessity of passing the variable as a argument.
Any subprograms thus declared may not themselves have other internal subprograms.
Although this approach avoid needing parameters, it does not permit the subprogram to be shared among several different main program (or other subprograms).
When including procedures in a module, the code must occur after a CONTAINS statement as in the example below.
In this approach, the procedures do not have access to variables or other entities in the calling code.
The following is an example of program which uses a module subroutine:
MODULE ONE
CONTAINS
SUBROUTINE TWO(A,B)
! body of subroutine code
END SUBROUTINE TWO
END MODULE
PROGRAM TEST3B
USE ONE
! body of main program
END PROGRAM TEST3B
The following is an example of program which uses this method of subprogram association:
PROGRAM TEST3B
! body of main program
END PROGRAM TEST3B
SUBROUTINE TWO(A,B)
! body of subroutine code
END SUBROUTINE TWO
SUBROUTINE ROOTS(A,B,C,PROOT,NROOT) REAL A,B,C,PROOT,NROOT,RAD RAD=SQRT(B*B-4.0*A*C) PROOT=(-B+RAD)/(2.0*A) NROOT=(-B-RAD)/(2.0*A) RETURN ENDThis code would be associated with the calling segment in any of the three ways already mentioned and, in the calling segment, to invoke this subroutine, one would find statements such as:
... READ(5,101)A,B,C CALL ROOTS(A,B,C,X1,X2) WRITE(6,102)X1,X2 ...NOTE: the formal (or ``dummy'') arguments PROOT and NROOT may be termed "output only" arguments (since they convey no input information to the subroutine), and correspond to the actual arguments X1 and X2.
PROGRAM MAIN REAL :: B(10),TOTAL ... CALL SUMARR(B,TOTAL) ... END ! SUBROUTINE SUMARR(A,SUM) REAL :: A(10),SUM INTEGER I SUM = A(1) DO I=2,10 SUM=SUM+A(I) END DO RETURN END
A programmer may want to use the same subprogram for arrays of different sizes. This can cause problems, however, since some Fortran compilers demand that the formal (subprogram) and actual (calling program) arrays be dimensioned exactly the same, eliminating the possibility of the subprogram array corresponding to two differently sized arrays in the calling program. To solve this dilemma, two general schemes are used. The older scheme involves passing the array dimension as one of the arguments. The newer scheme makes use of Fortran-90/95/2003 ``assumed-shape'' arrays.
In the first scheme, in the subprogram the array used as an argument is declared with a variable as the upper limit, for example,
REAL :: A(N)where both A and N are arguments passed into the subprogram.
NOTE: this type of indefinite dimensioning is only allowed in subprograms, and only for arrays which are arguments!!
For two and higher dimensional arrays, all the subscripts may be variables, but all these variables must be arguments passed from the calling program.
As an example of using this method, the following subroutine calculates the average of the numbers stored in an array.
SUBROUTINE AVER(ARR,N,AVE) REAL :: ARR(N),AVE,SUM INTEGER :: N,I SUM=ARR(1) DO I=2,N SUM=SUM + ARR(I) END DO AVE=SUM/N RETURN END
And in the calling program, one might have,
CALL AVER(GRADE,25,AVERAG)and elsewhere GRADE could be declared as follows:
REAL GRADE(25)Fortran-90/95/2003 has introduced an alternative to this method of indicating the dimension of array used as arguments. Such an array is called an assumed-shape array and is declared by using a colon (or colon with a preceding initial dimension value) in the declaration for each dimension of the array. For example, if D is an three-dimensional array being passed to a subroutine SUB1, the array could be declared as follows:
SUBROUTINE SUB1(D)
INTEGER, DIMENSION (:,:,:) :: D
In a case such as this, array D receives the exact values of the
three dimensions from the program segment which invokes SUB1.
This is done at compile time when the compiler checks the
array used as the actual argument.
This method of generalizing the size of the array being passed to the subprogram forces the compiler to determine additional information it does not available have from the code itself (as when the dimension is declared either with a constant or a variable being passed as a argument). As a result, the subprogram code must be integrated with the calling program in special ways. This may be done either by making such a subprogram an internal subprogram (cf. section 10.3.1 above), or by using a module (cf. section 10.3.2), or by including an interface block (cf. section 9.6) if the subprogram is written in external form (cf. section 10.3.3).
One includes an interface block in the calling program segment by placing it after any variable declarations. The interface itself only contains the header line of the subprogram, declaration statements for the arguments, and the subprogram END statement. For example,
PROGRAM SAMPLE1
INTEGER, DIMENSION (4, 5, 6) :: A
...
INTERFACE
SUBROUTINE SUB1(D)
INTEGER, DIMENSION (:,:,:) :: D
END SUBROUTINE
END INTERFACE
...
CALL SUB1(A)
...
END PROGRAM
An example of a subprogram which uses assumed shaped arrays as
well as array-handling features of Fortran-90/95/2003 (cf.
sections 9.11, 9.13)
is the following subroutine which exchanges the values
contained in two one-dimensional arrays (i.e., vectors).
SUBROUTINE SWAP(A,B)
REAL, DIMENSION(:) :: A, B
REAL, DIMENSION(SIZE(A)) :: WORK
WORK = A
A = B
B = WORK
END SUBROUTINE
For example,
optional type FUNCTION name ( formal argument list ) ... RETURN ENDSince there may be other keywords placed before the keyword FUNCTION, some authors recommend including the type within the variable declaration, explicitly giving the function name a specific data type. Using this approach, one would have:
FUNCTION name ( formal argument list ) data type of function name < declarations of arguments and other variables > ... RETURN END
NOTES:
a) In general, all the rules mentioned above for Fortran subroutines also apply to Fortran functions.b) Within the function, the function name is a local variable. Since functions are program units that return a specific value, the name (as a variable) must be given a value somewhere within the code of the function and this is the return value for the entire function when it is finished.
c) Unless designated as such, Fortran functions are not recursive, so the function should never attempt to call itself within the program code. Information about designating functions as recursive is given in the next chapter.
One could rewrite part of the sample subroutine in section 10.4 as a Fortran function as follows:
FUNCTION PROOT(A,B,C) REAL PROOT REAL A,B,C PROOT = (-B+SQRT(B*B-4.0*A*C))/(2.0*A) RETURN END(This is named PROOT for PLUS-ROOT, since the plus option was chosen in the computation of the root.)
Note that one could combine the first two lines of code into one line:
REAL FUNCTION PROOT(A,B,C)
NOTE: Since a function takes on a specific value, it must be of a specific data type. That type should normally be explicitly listed in the function's code in either way shown above.
Then, in the calling section, one could use the function with its arguments (similar to the way the library functions such as SQRT are used within an arithmetic statement), for example,
... READ(5,101)A,B,C X1=2.0*PROOT(A,B,C) ...The function's data type also plays an important rule in the calling section. If one uses the external method to associate subprograms with calling code (cf. section 10.3.3 above), one needs to convey to the calling segment the exact data-type of any user-defined function (unless one is using implicit typing). Thus, in any segment of code (main program, subroutine, function) which uses ("calls") a user-defined function, the function name should also be declared as a local variable in a standard type statement to avoid any type-mismatch errors. For example, in the section which uses the function PROOT given above, there should be a declaration statement,
REAL PROOT, A, B, CIf one regularly includes an IMPLICIT NONE statement (as is recommended as good practice by various authors), one will get a compiler error if a user-defined function name is not explicitly declared.
In some languages (e.g., C++, Ada, Pascal), the programmer has the choice of determining the passing scheme for each argument.
In other languages (e.g., Fortran, C), the user has no choice. The passing scheme is predetermined, but sometimes may be different for arrays than for scalars.
In Fortran, the specific passing methods are predetermined by the implementation, and no choice by the user is possible. In Fortran, the actual arguments are always changed in the calling segment, if the formal arguments were changed in the subprogram segment. But the methods used to produce the change in value may vary from implementation to implementation.
Most implementations of FORTRAN-IV and some implementations of Fortran-90/95/2003 use
call by result (value-result) for simple (scalar) variablesand
call by reference (address) for arrays
Most implementations of FORTRAN-77 and other implementations of Fortran-90/95/2993 use
call by reference for all arguments (scalars or arrays).
In call by result (value-result), the subprogram copies values from the actual arguments in the calling program. But the subprogram works with values in independent memory locations and the argument values may be changed independently of the variables originally associated with them in the calling program. When the subprogram is finished (i.e. when the RETURN or END statement is reached), the associated variables in the calling program are changed to correspond to the values the arguments received in the subprogram.
In call by reference (address), no new memory locations are allocated. Instead, a link is set up so that whenever a subprogram variable is referenced, the corresponding variable in the calling program is accessed and changed. (This scheme may result in one memory locations having two different "names" [one used by the main program and one by the subprogram], a phenomenon often termed "aliasing.")
Note that in both of these calling conventions, the variables can be changed upon completion of the subprogram. This is not true of the call-by-value arguments (used in C, C++, or Pascal).
In call by value, the subprogram sets up new independent memory locations, copies the values from the actual arguments (as in call-by-value-result), but does not change any variables in the calling program upon its completion.
To show that problems may occur if a programmer is unclear as to which argument passing scheme is used, and thus, to what is happening exactly between the main program and the subroutine, let us examine the following example, written in a pseudo-language.
function icrazy(i,j,k):integer i=j+k j=j+k icrazy=i+j+k k=j return endSuppose the main program code included the following:
n = 5 ivalue = icrazy(n,n,n) ivalue = ivalue + n write (ivalue)Then, depending on the type of "calling" method used, one gets three different answers!!
In the call by value case, the n in the calling code remains unchanged, whereas using call by value-result it changes. In the call by address case, the one memory location identified by n in the main program has three additional names in the function, i, j, and k. Therefore, whenever any one of them changes, the other three change values as well!
Since there is no uniformity as to how Fortran-90/95/2003 compilers actually pass scalar arguments, one should either test the argument passing scheme via some short program or avoid passing the same actual argument to different dummy arguments.
F(X) = X*Xor
G(X) = 2.0*X**3 + 3.0*X*X + 4.0*X - 2.5Then, in the code, one uses these functions as one would use any other functions. For example,
... A = F(2) - 3.0*G(3) FPX=(F(X+DELTAX)-F(X))/DELTAX ...The data type of the function ought to be explicitly declared and must be declared when using an IMPLICIT NONE statement.
Since statement functions are local to the program segment in which they are defined and cannot be passed as parameters, most authors recommend that programmers use regular functions (or even internal functions) and discourage their use.
Statement functions have been listed as an obsolescent feature in Fortran-95.
One uses an EXTERNAL statement if the function is user-defined.
In FORTRAN-77, one uses INTRINSIC if the function is part of the Fortran library functions. In Fortran-90/95/2003, one must use an INTRINSIC statement if there are specific intrinsic functions not defined by the standard but are specific to a local implementation, although it may also be used with other intrinsic functions (or omitted).
These specification statements are located with the other specification statements, before the first executable statement in the calling segment.
For example,
EXTERNAL F1,F2,F3 INTRINSIC SIN,COS ... CALL MYSUB1(SIN,X,Y,OUT1) CALL MYSUB1(COS,X,Y,OUT2) CALL MYSUB2(F2,Y) CALL MYSUB2(F3,Z) ...
Inside a procedure (subroutine or function), one must use an EXTERNAL statement again, this time listing the function arguments which have been passed if one wishes to pass these same arguments again (and they cannot otherwise be identified as subprograms).
For example, supposed F and SUB1 are intended to be dummy names for subprograms to be passed into SUB2.
SUBROUTINE SUB2(A,B,F,SUB1) EXTERNAL F REAL A,B CALL SUB1(F,A,B) RETURN ENDSince SUB1 was used in the CALL statement, the compiler recognizes it as a subroutine and it need not be listed in the EXTERNAL statement. Since, however, there is no indication that F is a subprogram (by default typing, it is a real variable), it must be listed in the EXTERNAL statement.
NOTE: In Fortran-90/95/2003 (and FORTRAN-77), one cannot pass as arguments generic function names, numeric type conversion functions, lexical comparison functions, or maximum and minimum functions. If one wishes to make use of certain intrinsic functions as arguments, one must use the appropriate "specific" name corresponding to the data type for which it will be used within the program segment. In most cases, general function names are equivalent to the specific name typed according to the default typing. In other words, since ABS(x) (a generic function name) is by default of type real (and not integer), if it is used as an argument, it will be assumed to be of type real rather than be a generic type that might conform to integer, double precision, or complex arguments. If one wished to use the corresponding function for integer or complex arguments, one must use the "specific" function name (see a complete Fortran-90/95/2003 manual).
ENTRY NEWSRT(A,B)
The entry name (e.g., NEWSRT) for a function should be declared as to its correct type after the header statement of the subprogram, along with any arguments in the argument list.
The ENTRY statement provides an alternate place to start the action of the subprogram. This can be useful especially if two or more subprograms share a significant amount of common code. Since multiple entry points, in effect, create different subprograms, some authors discourage using ENTRY and recommend using a MODULE or creating another subprogram which contains the common code and is called by other subprograms.
The SAVE statement comes before any DATA (see section 18.5) or executable statement and lists those variables whose values are to be saved. The name of a COMMON block (see section 18.6) may also be listed. If no variables are listed, all variable values are saved. As an example, if one wishes to save the values of variables A, B, and C, the following statement is used:
SAVE A, B, C
This page is maintained by Dennis C. Smolarski, S.J.
dsmolarski@math.scu.edu
© Copyright ©right; 1998-2005 Dennis C. Smolarski, SJ, All rights reserved.
Last changed: 23 June 2005.