Fortran allows one procedure to be used as the actual argument of another procedure. This provides a powerful facility, though one that most programmers use only rarely. Procedures are normally used to carry out a given set of operations on different sets of data; but sometimes you want to carry out the same set of operations on different functional forms. Examples include: finding the gradient of a function, integrating the area under a curve, or simply plotting a graph. If the curve is specified as a set of data points then you can simply pass over an array, but if it is specified by means of some algorithm then the procedure which evaluates it can itself be an actual argument.
In the next example, the subroutine GRAPH plots a graph of a function MYFUNC between specified limits, with its argument range divided somewhat arbitrarily into 101 points. For simplicity it assumes the existence of a subroutine PLOT which moves the pen to position (X,Y). Some other subroutines would, in practice, almost certainly be required.
SUBROUTINE GRAPH(MYFUNC, XMIN, XMAX) *Plots functional form of MYFUNC(X) with X in range XMIN:XMAX. REAL MYFUNC, XMIN, XMAX XDELTA = (XMAX - XMIN) / 100.0 DO 25, I = 0,100 X = XMIN + I * XDELTA Y = MYFUNC(X) CALL PLOT(X, Y) 25 CONTINUE ENDThe procedure GRAPH can then be used to plot a function simply by providing its name them as the first argument of the call. The only other requirement is that the name of each function used as an actual argument in this way must be specified in an INTRINSIC or EXTERNAL statement, as appropriate. Thus:
PROGRAM CURVES INTRINSIC SIN, TAN EXTERNAL MESSY CALL GRAPH(SIN, 0.0, 3.14159) CALL GRAPH(TAN, 0.0, 0.5) CALL GRAPH(MESSY, 0.1, 0.9) END REAL FUNCTION MESSY(X) MESSY = COS(0.1*X) + 0.02 * SIN(SQRT(X)) ENDThis will first plot a graph of the sine function, then of the tangent function with a different range, and finally produce another plot of the external function called MESSY. These functions must, of course, have the same procedure interface themselves and must be called correctly in the GRAPH procedure.
It is possible to pass either a function or a subroutine as an actual argument in this way: the only difference is that a CALL statement is used instead of a function reference to execute the dummy procedure. It is possible to pass a procedure through more than one level of procedure call in the same way. Continuing the last example, another level could be introduced like this:
PROGRAM CURVE2 EXTERNAL MESSY INTRINSIC SIN, TAN CALL GRAPH2(PRETTY) CALL GRAPH2(TAN) END SUBROUTINE GRAPH2(PROC) EXTERNAL PROC CALL GRAPH(PROC, 0.1, 0.7) ENDThus the procedure GRAPH2 sets limits to each plot and passes the procedure name on to GRAPH. The symbolic name PROC must be declared in an EXTERNAL statement as it is a dummy procedure: an EXTERNAL statement is required whether the actual procedure at the top level is intrinsic or external. The syntax of the INTRINSIC and EXTERNAL statements is given in section 9.12 below.
The name of an intrinsic function used as an actual argument must be a specific name and not a generic one. This is the only circumstance in which you still have to use specific names for intrinsic functions. A full list of specific names is given in the appendix. A few of the most basic intrinsic functions which are often expanded to in-line code (those for type conversion, lexical comparison, as well as MIN and MAX) cannot be passed as actual arguments.