Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
HP Fortran 90 Programmer's Reference: HP Fortran 90 Programmer's Reference > Chapter 7 Program units and procedures

Procedure interface

» 

Technical documentation

Complete book in PDF
» Feedback
Content starts here

 » Table of Contents

 » Glossary

A procedure interface is the information specified in a procedure reference, including the name of the procedure, the arguments, and (if the procedure is a function) the result. If the interface is explicit, all of the characteristics of the arguments and the result—type, kind, attributes, and number—are defined within the scope of the reference. If the interface is implicit, the compiler may be able to make sufficient assumptions about the interface to permit the procedure reference.

All procedure interfaces are implicit except for the following:

  • Intrinsic procedure

  • Internal procedure

  • Module procedure

  • Recursive function that specifies a result clause

  • External procedure whose interface is declared in an interface block

An explicit interface is required when:

  • The procedure reference uses the keyword form of an actual argument.

  • The procedure has OPTIONAL arguments.

  • Any dummy argument is an assumed-shape array or a pointer.

  • The result of a function is array-valued or a pointer.

  • The procedure is a character function, the length of which is determined dynamically.

  • The procedure reference is to a generic name.

  • The procedure reference implements a user-defined operator or assignment.

  • The procedure has the same name as an intrinsic procedure, but you want it to have precedence over the intrinsic; see “Availability of intrinsics”.

  • You want the compiler to perform argument-checking at compile-time.

The following sections describe the interface block and its use for creating:

  • Generic procedures

  • Defined operators

  • Defined assignment

Interface blocks

An interface block is used to provide an explicit interface for external procedures or to define a generic procedure. An interface block may appear in any program unit, except a block data program unit. It is specified in the specification part of the program unit.

The syntax for an interface block is:

INTERFACE [generic-spec]
[interface-body]...
[MODULE PROCEDURE module-procedure-name-list]
END INTERFACE
generic-spec

is one of:

  • generic-name

  • OPERATOR (operator)

  • ASSIGNMENT (=)

If generic-spec is omitted, then the MODULE PROCEDURE statement must also be omitted.

generic-name

is the name of the generic procedure that is referenced in the subprogram containing the interface block.

operator

is a unary or binary operator—intrinsic or user-defined—of the form:

.letter[letter]... .

interface-body

is:

function-statement
[specification-part]
end-function-statement

or

subroutine-statement [specification-part]
end-subroutine-statement

module-procedure-name-list

is a comma-separated list of names of module procedures that have generic-spec as a generic interface. Each module-procedure name must be accessible either by use association or—if this interface block is in a module that defines the module procedure—by host association.

If the MODULE PROCEDURE statement is present, then generic-spec must also be present.

The following example, proc_interface.f90, uses an interface block in the main program unit to provide an explicit interface for the function avg.

Example 7-8 proc_interface.f90

! Define an external function avg with one assumed-shape dummy
! argument. Note that the definition of the function must
! lexically precede its declaration in the interface block.
REAL FUNCTION avg(a)
REAL a(:)
avg = SUM(a)/SIZE(a)
END FUNCTION avg

PROGRAM main
REAL,DIMENSION(3) :: x
INTERFACE
REAL FUNCTION avg(a)
REAL, INTENT(IN) :: a(:)
END FUNCTION avg
END INTERFACE
x=(/2.0, 4.0, 7.0/)
PRINT *, avg(x)
END PROGRAM main

Here are the command lines to compile and execute the program, along with the output from a sample run:

$ f90 proc_interface.f90
$ a.out
4.33333

Generic procedures

The Fortran 90 concept of generic procedures extends the FORTRAN 77 concept of generic intrinsics to allow user-defined generic procedures. A procedure is generic if its name—a generic name—is associated with a set of specific procedures. Referencing the generic name allows actual arguments to differ in type, kind, and rank. The differences in the arguments determine which specific procedure is invoked.

A generic procedure is defined in an interface block that specifies its name and the interfaces of the specific procedures; see “Interface blocks”. The specific procedures within the interface block must all be subroutines or all functions. The interface for each procedure must differ from the others in one or more of the following ways:

  • The number of dummy arguments must differ.

  • Arguments that occupy the same position in the dummy argument lists must differ in type, kind, or rank.

  • The name of a dummy argument must differ from the names of the other dummy arguments in the argument lists of the other procedures, or all dummy arguments with the same name must differ in type, kind, or rank.

There may be more than one interface block with the same generic name, but the specific procedures whose interfaces appear in all such interface blocks must be distinguishable by the above criteria.

The MODULE PROCEDURE statement can be used to extend the list of specific procedures to include procedures that are otherwise accessible to the program unit containing the interface block. The MODULE PROCEDURE statement specifies only the procedure names; the procedure interfaces are already explicit. The MODULE PROCEDURE statement may appear only in an interface block that has a generic specification. Furthermore, the interface block must be contained either in the same module that contains the definitions of the named procedures or in a program unit in which the procedures are accessible through use association.

The following example assumes that two subroutines have been coded for solving linear equations: rlineq for when the coefficients are real, and zlineq for when the coefficients are complex. A generic name, lineq, is declared in the INTERFACE statement, enabling it to be used for referencing either of the specific procedures, depending on whether the arguments are real or complex:

INTERFACE lineq
SUBROUTINE rlineq(ra,rb,rx)
REAL,DIMENSION(:,:) :: ra
REAL,DIMENSION(:) :: rb,rx
END SUBROUTINE rlineq
SUBROUTINE zlineq(za,zb,zx)
COMPLEX,DIMENSION(:,:) :: za
COMPLEX,DIMENSION(:) :: zb,zx
END SUBROUTINE zlineq
END INTERFACE lineq

Defined operators

The OPERATOR clause can be used with the INTERFACE statement either to define a new user-defined operator or to extend—or overload—the behavior of an already defined or intrinsic operator. This second use is similar to defining a generic procedure (see “Generic procedures”). The re-defined operator becomes associated with a generic operator.

When the OPERATOR clause is present in the INTERFACE statement, the specific procedures within the interface block must all be functions. The functions can implement the operator for operands of different types, kinds, and ranks. These functions are restricted to one or two mandatory arguments, depending on whether the defined operator is unary or binary. The functions return the result of an expression of the form:

[operand] operator operand

Each dummy argument of the functions listed in the interface block must have the INTENT(IN) attribute. If operator is intrinsic, each specified function must take the same number of arguments as the intrinsic operator has operands. Furthermore, the arguments must be distinguishable from those normally associated with the intrinsic operation. However, argument keywords must not be used when the argument is specified as an operand to a defined operator.

If a user-defined operator is referenced by its generic name, the reference must resolve to a unique, specific function name. The selection of the function is accomplished by matching the number, type, kind, and rank of the operand with the dummy argument lists of the functions specified in the interface block. As with generic name references (see “Generic procedures”), exactly one procedure must match the properties of the operands, and the matching function is selected and invoked.

The following program, def_op.f90, illustrates a defined operation. The operation, .inrect., compares two derived-type operands. The one operand holds the x and y co-ordinates of a point on a graph, and the other holds the set of co-ordinates defining a rectangle. If the point is inside the rectangle, the operation evaluates to .TRUE.. The module in which the operation is defined also contains the definitions of the types of the operands.

As noted in the comments, when a module is defined in the same file as any USE statements that reference the module, the definition must lexically precede the USE statements. For information about modules and the USE statement, see “Modules”.

Example 7-9 def_op.f90

! Note that, if a module definition and any USE statements that
! reference the definition are in the same file, then the
! definition must lexically precede the USE statements.
MODULE coord_op_def
! Defines a logical operation for comparing two derived-type
! operands, as well as the derived types

! Define a derived type for the co-ordinates of a point
! in a graph
TYPE coord_pt
INTEGER :: x, y
END TYPE coord_pt

! define a derived type for the co-ordinates of a rectangle
TYPE rect_coords
TYPE(coord_pt) :: p1, p2
END TYPE rect_coords

! Interface block to define the logical operator .inrect.
! Evaluates to .TRUE. if the point operand lies inside
! the rectangle operand
INTERFACE OPERATOR (.inrect.)
MODULE PROCEDURE cmp_coords
END INTERFACE

CONTAINS
LOGICAL FUNCTION cmp_coords(pt, rect)
! returns .TRUE. if pt is inside rect

! arguments
TYPE (coord_pt), INTENT (IN) :: pt
TYPE (rect_coords), INTENT (IN) :: rect

cmp_coords = .FALSE. ! initialization
IF (pt%x >= rect%p1%x .AND. pt%x < rect%p2%x &
.AND. pt%y >= rect%p1%y .AND. pt%y < rect%p2%y) &
cmp_coords = .TRUE. ! pt is inside rect

END FUNCTION cmp_coords
END MODULE coord_op_def

PROGRAM main
! make the defined operation and the derived-type definitions
! of the operands accessible to this program unit
USE coord_op_def

! specify a value for the rectangle co-ordinates
TYPE (rect_coords) :: rectangle = &
rect_coords(coord_pt(3, 5), coord_pt(7, 10))
TYPE (coord_pt) :: point ! user will specify value for this

PRINT *, "Enter two co-ordinates (integers) in a graph:"
READ *, point

! perform defined operation
IF (point .inrect. rectangle) THEN
PRINT *, "The point lies inside the rectangle."
ELSE
PRINT *, "The point lies outside the rectangle."
END IF
END PROGRAM main

Here are the command lines to compile and execute the program, along with the output from a sample run:

$ f90 def_op.f90
$ a.out
Enter two co-ordinates (integers) in a graph:
4,8
The point lies inside the rectangle.

Defined assignment

The ASSIGNMENT clause can be used with the INTERFACE statement to specify one or more subroutines that extend—or overload—the assignment operator. Each subroutine must have exactly two arguments. The first argument can have either the INTENT(OUT) or the INTENT(INOUT) attribute; the second argument must have the INTENT(IN) attribute. The first argument corresponds to the variable on the left-hand side of an assignment statement, and the second to the expression on the right-hand side.

Similarly to generic names and defined operators, there can be more than one defined assignment, but each occurrence of the assignment statement must resolve to a unique, specific subroutine. The subroutine whose dummy arguments match the left-hand and right-hand sides of the assignment statement in kind, type, and rank is selected and invoked from the list of subroutines specified in the defined-assignment interface block.

The following example, def_assign.f90, illustrates defined assignment. The assignment consists of performing an elementary statistical analysis of the data on the right-hand operand and storing the results in the left-hand operand. As noted in the comments, when a module is defined in the same file as any USE statements that references the module, the definition must lexically precede the USE statements. For information about modules and the USE statement, see “Modules”.

Example 7-10 def_assign.f90

! Note that, if a module definition and any USE statements that
! reference the definition are in the same file, then the
! definition must lexically precede the USE statements.
MODULE def_assign_stats
! Defines the derived-type operands and extends the assignment
! operator to perform a statistical analysis of the data in
! raw_data

! input data
TYPE raw_data
REAL :: x(100) ! values to be averaged
INTEGER :: n ! number of values assigned to x
END TYPE raw_data

! output data
TYPE stats_data
REAL :: sum, max, min, avg ! statistical results
END TYPE stats_data

! interface block to extend the assignment operator
INTERFACE ASSIGNMENT (=)
MODULE PROCEDURE do_stats
END INTERFACE

CONTAINS
SUBROUTINE do_stats(lside, rside)
! define the operations that are performed when
! rside is assigned (=) to lside

TYPE (raw_data), INTENT (IN) :: rside
TYPE (stats_data), INTENT (OUT) :: lside

! use a structure constructor for initialization
lside = stats_data(0, 0, 9999999.9, 0)

! find the sum, max, and min
DO i = 1, rside%n
lside%sum = lside%sum + rside%x(i)
IF (lside%max < rside%x(i)) lside%max = rside%x(i)
IF (lside%min > rside%x(i)) lside%min = rside%x(i)
END DO

lside%avg = lside%sum / rside%n ! the average
END SUBROUTINE do_stats
END MODULE def_assign_stats

PROGRAM main
! Make the defined assignment and the definitions of the
! derived-type operands in the assignment accessible to
! this program unit
USE def_assign_stats

TYPE (raw_data) :: user_data ! right-hand side of
! assignment
TYPE (stats_data) :: user_stats ! left-hand side of assignment

CALL get_data(user_data) ! collect user data
user_stats = user_data ! defined assignment statement

PRINT *, "Maximum =", user_stats%max
PRINT *, "Minimum =", user_stats%min
PRINT *, "Sum =", user_stats%sum
PRINT *, "Average =", user_stats%avg
END PROGRAM main

SUBROUTINE get_data(data)
! this subroutine stores user-input values and the number
! of values stored in data

! make the definition of raw_data accessible
USE def_assign_stats
TYPE (raw_data) :: data ! the argument
REAL :: val
INTEGER :: i

! get user input
DO i = 1, 100
PRINT *, "Enter a positive real (negative to quit):"
READ *, val
IF (val < 0.0) EXIT ! negative, so leave
data%x(i) = val
data%n = i ! count of values so far
END DO
END SUBROUTINE get_data

Here are the command lines to compile and execute the program, along with the output from a sample run:

$ f90 def_assign.f90
$ a.out
Enter a positive real (negative to quit):
25.5
Enter a positive real (negative to quit):
35.5
Enter a positive real (negative to quit):
45.5 Enter a positive real (negative to quit):
-1
Maximum = 45.5
Minimum = 25.5
Sum = 106.5
Average = 35.5
Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© Hewlett-Packard Development Company, L.P.