Subprograms

A part of the program that conceptually belongs together, or that will be used more than once, possibly with minor variations, can be given a name, and be invoked by that name. There are two kinds of subprograms: functions are the subprograms that calculate one value; subroutines are the subprograms that compute multiple values, or make changes to program data.

Subprograms can be placed in separate files, or they can be in the same file as a main program:

      PROGRAM prog
      ...
      END
      SUBROUTINE subr
      ...
      END
      FUNCTION fun
      ...
      END

The order in which main program and subprograms are placed is completely irrelevant. In particular, unlike in such languages as Pascal or C, subprograms can be used before they are defined. (In C terminology, not even prototypes are needed.)

Functions

The introduction of functions is one way to give a name to a part of the computation that mostly serves to compute a single value.

User defined functions can be used in any expression, in the same way as library functions are:

      x = sin(3.57)+myfun(4.023)

This line, or more generally the (sub)program it appears in, is called the calling site of the function. There is also the defining site of the function: its actual definition.

Often, it is not necessary to declare the type of library functions, but user-defined functions need to be declared: eg,

      REAL myfun

This function is defined somewhere in the source as a separate subprogram:

      FUNCTION myfun(x)
      REAL myfun,x
      ...
      myfun = <some expression using x>
      RETURN
      END

This definition can be in a different file. As a result, the compiler will not complain processing the use of the function if you forget actually to define the function. Only when you link your program will you get an error message about a missing function.

Function arguments

A function can have zero or more arguments. For instance, a function named random will likely have no arguments. Even if there are no arguments, the parentheses are mandatory at both calling and defining site. Example:

      FUNCTION random()
      random = <some expression>
      RETURN
      END
      ....
      x = random()

If a function has arguments, these must be declared in the function definition, just as any local variables.

Type declaration

At the defining site of the function its type needs to be declared. This can be in two ways: you can write

      type FUNCTION name (args)

or you can write

      FUNCTION name (args)

and let the name be declared implicitly or explicitly:

      type name

If you use the first form, you cannot have the name also appear in an explicit type statement.

Result assignment

The value computed in a FUNCTION subprogram is passed back to the calling site as follows: it is assigned to the function name. Example:

      FUNCTION comput(val)
      comput = <some expression using val>
      RETURN
      END

The assignation can happen in other ways, for instance by passing the function name as argument to a subroutine

      CALL comput2(comput)

that assigns a value to its argument. One could even write

      FUNCTION iwhere(arg,arr,len)
      DIMENSION arr(len)
      DO 10 iwhere=1,len
         IF (arr(iwhere).EQ.arg) RETURN
10    CONTINUE
      END

In addition to the normal result assignment, a function can also return results by changing the value of its arguments. While this is the accepted way for subroutines to pass back information, for functions this is called a side-effect, and it is not a recommended programming practice. If you do use side effects, make sure they don't alter variables used in the same expression as the function call: in

      X = Y + F(Y)

it would be a bad idea if F altered its argument, since this would make the value of the right-hand-side expression dependent on the evaluation order, which is not prescribed in the language standard.

Statement functions

For a computation that can be expressed in a single statement, and that occurs several times in one program unit, a statement function can be defined. Example:

      AVG(X,Y) = (X+Y)/2.0

This function declaration has to come after any other non-executable statement, and before the first executable statement. Now you can use the function so defined as part of any expression in this subprogram:

      Z = AVG(3.0,2*X) + 5.1

In addition to the function definition, you need to declare the type of the function name and its arguments in the function definition. You can not declare a statement function as EXTERNAL.

Subroutines

Subroutines look a lot like functions, but they differ in a few ways. Instead of delivering a single value that can be used in an expression at the calling site, they take some data of the calling site and process or alter it in some way.

Example: with the definition

      SUBROUTINE out(x)
      PRINT *,'The final result is ',x
      RETURN
      END

the call

      CALL out(3.7)

will give the same result as writing

      PRINT *,'The final result is ',3.7

Another example: if a subroutine is invoked by

      CALL subr(x,y)

and its definition is:

      SUBROUTINE subr(a1,a2)
      a1 = 1.
      a2 = 3.
      RETURN
      END

then the call statement is equivalent to

      x = 1.
      y = 3.

Note that the subroutine definition does not contain an assignment to the subprogram name, the way a function definition would have. For as far as the defining site is concerned, that is the only difference between a function and a subroutine.

Call

Whereas a function was called by using its name in the right-hand-side of an expression, a subroutine is invoked with a CALL statement:

      CALL subr(arg1,arg2,arg3)

When the call statement is encountered, control is transferred to the subroutine body. That is, the statements in the subroutine body are executed before the statement after the call is tackled.

Definition

A subroutine can have zero or more arguments. If the number of arguments is zero, no parentheses need be given both for the definition and the call (unlike with functions, where an empty pair is necessary both at the defining and using site).

General discussion

Local variables

Above we saw how subprograms are placed alongside, not inside, other subprograms and the main program. Among other things, this implies that Fortran subprograms are almost completely shielded from the main program. There is no immediate sharing of data.

Thus, any variables in the main program are (unless passed as argument or placed in COMMON) invisible to the subprograms. Conversely, any variables declared in a subprogram are completely local to that subprogram. In particular, the same variable names can be used, even with different defining types, in the main program and subprograms. The same holds for labels.

Example of local variables

A function for computing the factorial of an integer number would feature the following loop:

      factor = 1
      DO 10 i=1,n
         factor = factor * i
10    CONTINUE

The variable n is the input, and factor is the result to be returned, but i has no meaning outside the computation of the factorial. Hence we make it a local variable:

      FUNCTION factor(n)
      INTEGER factor,n,i
      factor = 1
      DO 10 i=,n
         factor = factor * i
10    CONTINUE
      RETURN
      END

Argument passing

Supplying a variable as argument to the invocation of a subprogram makes that variable known and accessible to the subprogram body. Example:

      x = 1.5
      CALL func(x)
      ...
      SUBROUTINE func(arg)
      ...
      arg = 2.3
      ...
      END

When the execution of the statements in func starts, the argument arg has value 1.5. When the subroutine's execution has finished, the variable x in the main program has a value of 2.3.

There are many points to be addressed in passing array arguments. This will be done in the section on arrays.

Actual and formal (dummy) arguments

The parenthesised identifiers in the SUBROUTINE or FUNCTION line are called the dummy arguments of the subprogram (this is actually a somewhat silly terminology, only used in Fortran; most other languages call these the formal arguments). These behave a bit like local variables of the subprogram. You can for instance use them in any right-hand-side expression. Whether you can use them on the left-hand-side depends on the actual arguments.

Whatever is supplied in a CALL statement or in a function call, corresponding to the dummy arguments are called the actual arguments. As we saw in the examples above, actual arguments can be constants or variables; other possibilities are expressions, array elements, even subprogram names. In the case of variables (or array elements, or in fact whole arrays), the subprogram can have an assignment to the corresponding dummy variable, though this is not recommended for functions; in the case where the actual argument is a constant or expression, the language standard prohibits assigning to the corresponding dummy argument.

Note that the compiler is unable to detect violations against this prohibition; typically such programs as ftncheck detect this kind of error. (This particular error could lead in certain Fortran compilers to the value of constants being changed; certainly one of the strangest bugs imaginable.)

The mechanism by which Fortran associates actual arguments to dummy arguments is by reference; Fortran is said to use `call by reference'. To understand this, consider that a variable x is a reference to a value. Instead of talking about the value, we only refer to it by a symbolic name. Supplying a variable as actual argument to a subprogram makes the corresponding dummy argument another reference to the same value.

Another error connected to passing arguments is `aliasing'. If a subroutine is called with identical variable actual arguments

      CALL subr(x,x)

the corresponding dummy arguments are now aliases: in the subprogram

      SUBROUTINE subr(a1,a2)

the dummy arguments a1 and a2 now refer to the same value. This is no problem if they only appear in right-hand sides, but in case of assignments

      a1 = ....
      a2 = ....

the result is most likely not what was intended.

Subprograms without arguments

It is possible for a subroutine or function to have no arguments. In that case the definitions look like

      FUNCTION myfun()
      ...
      SUBROUTINE mysub
      ...

and likewise, their applications look like

      x = myfun()
      ...
      call mysub

Example of a subprogram without arguments

A function for computing a random number needs no input; it only returns a result:

      FUNCTION random()
      READ random
      ...
      END

We compute the random number by remembering a seed value, and transforming this each time the function is called; the transformation needs two suitably chosen integers:

      INTEGER seed,modulus,multiplier
      SAVE seed
      PARAMETER (modulus=27, multiplier=13)
      seed = MOD(seed*multiplier,modulus)

The requested random number is then a scaling of the integer seed value; we also use a DATA statement to initialise the seed:

      DATA seed/4/
      random = seed / REAL(modulus)

See below for a further elaboration of this example.

Data in COMMON

The variables in Fortran subprograms or the main program are completely invisible to other subprograms. We have already seen how variables can be made accessible by passing it as arguments. There is another way, namely by putting the data in a COMMON block.

      PROGRAM p
      COMMON /global/x,y
      ...
      END
      SUBROUTINE s
      COMMON /global/a,b
      ...

The common block is identified by its name; you are free to give the variables different names in different subprograms, but the number of variables should be the same every time.

In any common block, all variables should have the same type. You are allowed to mix scalar and array variables of the same type.

More than one common block can be placed on one line:

      COMMON /rglobal/rmax,rmin,/iglobal/imax,imin

Data in common can be initialised with a DATA statement, but this requires a special type of program unit: the BLOCK DATA unit. This can only have non-executable statements and it ends with END, without a RETURN. Example:

      BLOCK DATA initglobal
      COMMON /rglobal/rmax,rmin,/iglobal/imax,imin
      DATA imin,imax,rmin,rmax/1,-1,1.0,-1.0/
      END

There can be more than one block data unit in a program.

All examples of COMMON blocks so far were of named common; there is also blank common. Example:

      COMMON x,y,z

While there can be arbitrarily many named common blocks, there can be only one blank common block. Blank common can not be initialised in BLOCK DATA units.

Example of the use of common blocks

In the example of a random number generator above, we initialised the seed in a DATA statement. The problem with that is that the sequence of random numbers will be the same each time the program is run. To prevent this, we want a subroutine

      CALL setrandomseed(5)

for setting the initial seed value. This subroutine communicates with the random function by using a COMMON block:

      SUBROURINTE setrandomseed(s)
      INTEGER s,seed
      COMMON /random/seed
      seed = s
      RETURN
      END

and

      FUNCTION random(n)
      ...
      INTEGER seed
      COMMON /random/seed

Note that the following is not allowed:

      SUBROURINTE setrandomseed(seed)
      INTEGER seed
      COMMON /random/seed

Save statement

When a subprogram's execution has finished, the values of all local variables become undefined, according to the language standard. In practice, many compilers will keep the values around, and the next time the subprogram is executed, the local variables will have this last value.

If you want to be sure variables retain their value from one incarnation of the subprogram to the next, you have to declare them in a SAVE statement. Example:

      SUBROUTINE readbigger
      SAVE biggest
      READ *,rnew
      IF (rnew.GT.biggest) THEN
         biggest = rnew
         PRINT *,'Biggest value so far: ',biggest
      END IF
      RETURN
      END

In this and similar examples you do need to initialise the saved variable in a DATA statement. For example, if all values to be read are positive you could declare

      SUBROUTINE readbigger
      DATA /biggest/-1.0
      SAVE biggest
      ...

External and Intrinsic

Function and subroutine names can be passed as arguments to other subprograms. For this, they first need to be declared at the calling site of the subprogram they are being passed to, in an INTRINSIC statement for library functions, and an EXTERNAL statement for user-defined subprograms.

      EXTERNAL myfun
      ...
      res = integrate(myfun,0.0,1.0)

The EXTERNAL statement is a specification statement.

You cannot declare statement functions as EXTERNAL.

Return

If the subroutine body contains a RETURN statement, this causes control to be transferred back to the calling site; specifically, the statement after the call will be executed. Example:

      SUBROUTINE mysub
      <statement block1>
      IF (condition) RETURN
      <statement block2>
      RETURN
      END
      ...
      CALL mysub
      <next statement>

The call statement causes the subroutine to be executed, specifically, the first block of statements is executed. If then the condition tested is true, execution of the subroutine body is terminated, and control is transferred back to the calling site. Specifically, the statement after the call is then executed.

There is also the

      RETURN 3

syntax. This is not a recommended programming practice.

Recursion

Some problems naturally call for a function referring to itself, eg n factorial is n times n-1 factorial, with 1 factorial being 1. In Fortran77, functions and subroutines are not allowed to call themselves, not even indirectly. Usually the compiler will complain if you write a function that calls itself, but if you have two subprograms, prog1 calling prog2, and the other way around, and they are in separate files, the compiler cannot detect this `daisy-chain recursion'.

Fortran90 does have recursion.