The INTERFACE statement is the first statement in an interface block. The interface block is a powerful structure that was introduced in FORTRAN 90. When used, it gives a calling procedure the full knowledge of the types and characteristics of the dummy arguments that are used inside of the procedure that it references. This can be a very good thing as it provides a way to execute some safety checks when compiling the program. Because the main program knows what argument types should be sent to the referenced procedure, it can check to see whether or not this is the case. If not, the compiler will return an error message when you attempt to compile the program. Also with just a slight variation, it can then be used to create generic functions for use inside of a program unit.
The use of the interface block to provide knowledge of referenced program units is pretty easy. You begin the interface block with the INTERFACE statement which should be placed right after all of the non executable statements ( program, use, implicit, type declarations, etc. ) in a program unit. Then, following the interface statement, the subroutine or function declaration along with the type statements for the dummy arguments used in the procedure should be included. Note that the intent of the dummy arguments should also be included. The type statements are followed by the appropriate END FUNCTION of END SUBROUTINE statement. The conclusion of the interface block will then be an END INTERFACE statement. With this in mind, let's say that I wanted to write a function that would take two one dimension arrays (a and b), add their elements individually, multiply the sums by a constant (n) and return values as a one-dimensional array. The interface block for this subroutine would then look like this.
Interface Function vector_add(a,b,c,n) real, intent(in) :: a(:),b(:),n real vector_add(size(a)) end function vector_add end interface
Of special interest in this example is the fact that no constant needs to be passed to the subroutine to give the size of the arrays. The size of these arrays will automatically be passed to the subroutine when the call is issued. Another interesting thing is to take note of how the size function is used to define the size of the result array vector_add.
To extend the use of the interface block for defining generic functions requires only a few small steps beyond what you have already learned. First, instead using just the plain interface statement, you use an interface statement that includes the name you wish to give to the generic procedure. The interface block itself will then contain the detailed description each specific function and its dummy arguments that can be referenced using the generic name. For instance, lets say that I wrote two functions to take care of the case described above. The one function ( rvector_add ) would take care of the case when the addition and multiplication would be done on a set of real variables and the second function ( ivector_add ) would take care of the case when the array's are of type integer. With the use of the interface block, I will then make it possible to call either of these functions using the generic name vector_add.
Interface vector_add Function ivector_add(a,b,n) Implicit none integer, intent(in) :: a(:),b(:),n integer ivector_add(size(a)) end function ivector_add function rvector_add(a,b,n) implicit none real, intent(in) :: a(:),b(:),n real rvector_add(size(a)) end function rvector_add end interface vector_add
Before I finish this discussion on generic functions, there is one question that I haven't answered about them. How will the compiler know which one of these functions to use when a call is issued to a generic function? Well, when the call is made, the compiler will look at the argument types that are going to be passed to the function. The compiler then matches the actual argument types with the types given to the dummy arguments in the interface block and passes the arguments onto the appropriate function. So in reference to the above example, if a call is made using all integer variables their values will get passed onto ivector_add while if all real arguments are used, the values will be passed to rvector_add.
There are two other powerful functions that the interface statement can perform. The details of the how and why are beyond the scope of an introductory course in FORTRAN programming, but they are something to keep in mind if you choose to pursue a career in programming.
The first additional function that the interface statement can perform is to provide a way to extend the performance of the assignment operator ( the equals sign ). Our general conception of this operator is that it just stores some value into a memory location associated with some variable. However when you think about it, the assignment operator will actually perform operations more complicated than that. For instance, when a real number is truncated to be stored as an integer or when spaces are added on to a character string to completely fill out the its allotted memory space. The interface statement can extend such abilities to instances that involve your own derived types. Like I said earlier this is something that beginning programmers really don't need to be concerned with, but it is something to file back in the corner of your mind for future reference.
The last function that the interface statement can preform is the extension of FORTRAN's intrinsic operators ( +, -, .lt., .eq., etc. ) or the ability to create your own operators. For example, you could create your own operator called .pi. that you could use to transform angles input in degrees to their corresponding value in radians. Often times, things like that are just as easily carried out using a call to a function or a subroutine so don't be concerned about the details. Just remember that the power exists to do such things in FORTRAN.
lecture thirty six
examples: funspeed.f and pointers.f
Written by Jason Wehr: firstname.lastname@example.org and Maintained by John Mahaffy : email@example.com