A generic subroutine is one which has an argument (or arguments) which may be one of a number of different Fortran data types.
As an example, consider a subroutine which initialises every element in an array to zero. One might want a different version of the routine for initializing a double precision array, an integer array and a real array. The following subroutines would need to be written:
ZEROD( N, DARR ) Zero every element in a DOUBLE PRECISION array ZEROI( N, IARR ) Zero every element in an INTEGER array ZEROR( N, RARR ) Zero every element in a REAL array
The integer routine might contain the following code (in a file called zeroi.f):
SUBROUTINE ZEROI( N, ARRAY ) *+ * Name: * ZEROI * Purpose: * Zero all the elements of an4 INTEGER array * Invocation : * CALL ZEROI( N, ARRAY ) * Description : * This sets all the elements of an INTEGER array to zero * Arguments: * N = INTEGER( Given ) * Dimension of array * ARRAY( N ) = INTEGER( Given and Returned ) * The array to be zeroed * " * (the rest of the standard prologue) * " * Type Definitions: IMPLICIT NONE * Arguments Given: INTEGER N * Arguments Given and Returned: INTEGER ARRAY( N ) * Local Variables: INTEGER I ! Array index *- DO I = 1, N ARRAY( I ) = 0 END DO END
The REAL and DOUBLE PRECISION versions of the routine would have to be written in a similar way, and this obviously involves a lot of duplication of effort. The situation gets even worse if other versions of the routine (such as BYTE, INTEGER*2) are needed. Also, it is very difficult and tedious to keep all the versions in step if they have to be edited individually when the routines are changed.
The GENERIC utility is a labour-saving device which enables all the various types of routines to be constructed automatically from one master routine. If any changes become necessary, only this one master routine needs to be edited.
To use the GENERIC utility, the routine listed above is replaced by the following (in a file called zero.gen):
SUBROUTINE ZERO<T>( N, ARRAY ) *+ * Name: * ZERO<T> * Purpose: * Zero all the elements of a <COMM> array * Invocation : * CALL ZERO<T>( N, ARRAY ) * Description : * This sets all the elements of a <COMM> array to zero * Argument: * N = INTEGER( Given ) * Dimension of array * ARRAY( N ) = <TYPE>( Given and Returned ) * The array to be zeroed * " * (the rest of the standard prologue) * " * Type Definitions: IMPLICIT NONE * Arguments Given: INTEGER N * Arguments Given and Returned: <TYPE> ARRAY( N ) * Local Variables: INTEGER I ! Array index *- DO I = 1, N ARRAY( I ) = 0<CONST> END DO END
This is a ``generic routine.'' Other examples of generic routines include the DAT_ routines in the Hierarchical Data System (SUN/92) and the PAR_ routines of the ADAM parameter system (SSN/29).
The items in angle brackets, , are ``tokens'' which the GENERIC utility replaces when it converts the routine into one of a given type. In the above example, the tokens would be replaced as follows.
Token Double precision Integer Real replacement replacement replacement <T> D I R <TYPE> DOUBLE PRECISION INTEGER REAL <COMM> DOUBLE PRECISION INTEGER REAL <CONST> .0D0 (blank) .0E0
The types are generated by issuing the following command.
% generic -t dir zero.gen
More details on the use of the GENERIC utility, and a full list of
tokens and types, are given in the rest of this document.
GENERIC --- A Utility for Preprocessing Generic Fortran and C Subroutines