Fortran procedure pointer to routines in a derived type

In Fortran, I need a procedure pointer inside a derived type that can point to one of several routines. This problem seems common for SO:

Fortran save procedure as a property of a derived type

Overloading Related Types in Fortran 2003

There is no corresponding subroutine for a related generic subroutine call of this type

Generic String Binding Procedures with Procedure Arguments

Type to bind procedure as arguments

to name a few. The answer to this question for functions is provided very well in the first link.

However, I still do not understand the methodology for developing such code in the event that a type-bound procedure pointer points to a subroutine. The difficulty is that there is no type associated with the returned one (since nothing is returned ")".

I would also like to point out a nuance that, although a simple solution may exist in the newer fortran standard (2003,2008), this solution may not work on all compilers, which may be problematic in the future. Therefore, I am interested in compilers.

I have a small code (shown below) that currently works, but in my large code I get an internal compiler error (also shown below) in a file where I use method pointers in derived types. My question is: what can I do with the code below

1) Strictly use explicit interfaces

2) Maximize the information passed to the compiler

3) Make sure that the code is ported between as many compilers as possible (i.e. uses fortran 90/95).

To what extent can this be accomplished (1 most important)? Is it possible to satisfy all these criteria above? I know that “satisfying all these criteria” is subjective, but I would say that the answer is “yes” for the same question regarding functions instead of routines.

gcc version 5.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project) 

Small code:

  module subs_mod implicit none public :: add,mult contains subroutine add(x,y,z) implicit none integer,intent(inout) :: x integer,intent(in) :: y,z x = y+z end subroutine subroutine mult(x,y,z) implicit none integer,intent(inout) :: x integer,intent(in) :: y,z x = y*z end subroutine end module module type_A_mod use subs_mod implicit none public :: type_A,init,operate type type_A procedure(),pointer,nopass :: op end type contains subroutine init(A,op) implicit none external :: op type(type_A),intent(inout) :: A A%op => op end subroutine subroutine operate(A,x,y,z) implicit none type(type_A),intent(in) :: A integer,intent(inout) :: x integer,intent(in) :: y,z call A%op(x,y,z) end subroutine end module program test use type_A_mod use subs_mod implicit none type(type_A) :: A integer :: x call init(A,mult) call operate(A,x,3,5) write(*,*) 'x = ',x end program 

Compiler error in large code:

  f951.exe: internal compiler error: Segmentation fault libbacktrace could not find executable to open Please submit a full bug report, with preprocessed source if appropriate. See <http://sourceforge.net/projects/mingw-w64> for instructions. 

UPDATE

Here's a small modification that gives the compiler more information, but I have not tried this in large code. However, this seems arbitrary, and I have no idea whether this will help or not.

  ... function add(x,y,z) result(TF) ... logical :: TF x = y+z TF = .true. end function function mult(x,y,z) result(TF) ... logical :: TF x = y*z TF = .true. end function end module module type_A_mod ... type type_A procedure(logical),pointer,nopass :: op end type ... subroutine init(A,op) implicit none logical,external :: op ... end subroutine subroutine operate(A,x,y,z) ... logical :: TF TF = A%op(x,y,z) end subroutine end module program test ... end program 

SOLUTIONS COMMENTS Just to comment on a solution (provided by @IanH): there was one more wrinkle, and it was that I had some derived types included in the abstract interface, which according to the New Fortran 2003 functions , the Import statement should be included to tell an abstract interface about any incoming derived types. Here is a small working example that applies to large code, reduces the internal compiler error I had :)

  module DT_mod implicit none private public :: DT type DT integer :: i end type contains end module module subs_mod use DT_mod implicit none private public :: add,mult,op_int abstract interface subroutine op_int(d,x,y,z) import :: DT implicit none type(DT),intent(inout) :: d integer,intent(inout) :: x integer,intent(in) :: y,z end subroutine end interface contains subroutine add(d,x,y,z) implicit none type(DT),intent(inout) :: d integer,intent(inout) :: x integer,intent(in) :: y,z x = y+z d%i = 1 end subroutine subroutine mult(d,x,y,z) implicit none type(DT),intent(inout) :: d integer,intent(inout) :: x integer,intent(in) :: y,z x = y*z d%i = 2 end subroutine end module module type_A_mod use DT_mod use subs_mod implicit none private public :: type_A,init,operate type type_A procedure(op_int),pointer,nopass :: op end type contains subroutine init(A,op) implicit none procedure(op_int) :: op type(type_A),intent(inout) :: A A%op => op end subroutine subroutine operate(A,d,x,y,z) implicit none type(DT),intent(inout) :: d type(type_A),intent(in) :: A integer,intent(inout) :: x integer,intent(in) :: y,z call A%op(d,x,y,z) end subroutine end module program test use type_A_mod use subs_mod use DT_mod implicit none type(type_A) :: A type(DT) :: d integer :: x,y,z y = 3; z = 5 call init(A,mult) call operate(A,d,x,y,z) write(*,*) 'x,y,x = ',y,z,x write(*,*) 'd%i = ',d%i end program 

Any help is greatly appreciated.

+5
source share
1 answer

Procedure pointers were not part of the standard language until Fortran 2003, so if you want to use them at all, then Fortran 95 compatibility doesn't matter.

An internal compiler error is a compiler error, regardless of the source provided to the compiler.

There is no such thing as a type binding procedure pointer. You either have a type-related procedure — this is a thing declared after CONTAINS in a derived type construct, or you have a pointer to a procedure that can be a component of a type or a stand-alone object. A procedure pointer, which is a component, is part of the value of an object of a derived type — it can be associated with various procedures at run time. A type-related procedure is a fixed property of a type declaration.

If you want the procedure pointer (or dummy procedure) to have an explicit interface, then you must specify the interface name inside the bracket of the statement of the procedure statement.

 procedure(interface_name_goes_here) [, pointer, ...] :: thing_being_declared 

The provided interface name can be the name of an available specific procedure (including the one previously declared by the declaration operator of another procedure) or the name of an abstract interface.

(If the interface name in the procedure declaration instruction is a type, as for the component in your code example, the declared procedure is a function with the result of this type with an implicit interface.

If the interface name in the procedure declaration instruction is completely absent, the declared procedure can be a function or a subprogram (its subsequent use in it must be consistent with one or another) with an implicit interface.)

So, suppose you want to declare a procedure pointer component with an explicit interface to a function (as opposed to the question header) with the same characteristics as add or mult in the second code fragment:

 TYPE type_A PROCEDURE(the_interface), POINTER, NOPASS :: op END TYPE type_A ABSTRACT INTERFACE FUNCTION the_interface(x, y, z) RESULT(tf) IMPLICIT NONE ! function modifying arguments - poor style!!! INTEGER, INTENT(INOUT) :: x INTEGER, INTENT(IN) :: y, z LOGICAL :: tf END FUNCTION the_interface END INTERFACE 

If you want the procedure pointer to be a subroutine with an explicit interface (which is preferable to a function that changes its arguments), change the abstract interface accordingly.

The mannequin in the init routine does not have to be a pointer - inside init you do not change what the op link refers to - you just point to it with another pointer:

 PROCEDURE(the_interface) :: op 

When your dummy procedures and procedure pointers are declared with an explicit interface, I expect a sensible compiler to diagnose any inconsistencies in the characteristics.

+5
source

Source: https://habr.com/ru/post/1246983/


All Articles