dantopa
dantopa

Reputation: 635

How to pass subroutine names as arguments in Fortran?

What is the syntax for passing subroutine names as arguments? Schematically:

  .
  .
call action ( mySubX ( argA, argB ) )
  .
  .

subroutine action ( whichSub ( argA, argB ) )
  ...
call subroutine whichSub ( argA, argB )
  ...
end subroutine action

The goal is to have call subroutine whichSub ( argA, argB ) act as call subroutine mySubX ( argA, argB ). My preference is to avoid avoid passing a switch parameter and then use SELECT CASE.

Upvotes: 7

Views: 9692

Answers (2)

It is

call action(mySubX)

provided action looks as

subroutine action(sub)
  !either - not recommmended, it is old FORTRAN77 style
  external sub
  !or - recommended
  interface
    subroutine sub(aA, aB)
      integer,intent(...) :: aA, aB
    end subroutine
  end interface
  ! NOT BOTH!!

  call sub(argA, argB)

provided action knows what to put there as argA, argB to represent aA, aB.

Otherwise, if you want to pass also the arguments

call action(mySubX, argA, argB)

subroutine action(sub, argA, argB)
  !either - not recommmended, it is old FORTRAN77 style
  external sub
  !or - recommended
  interface
    subroutine sub(aA, aB)
      integer,intent(...) :: aA, aB
    end subroutine
  end interface

  integer, intent(...) :: argA, argB

  call sub(argA, argB)

I don't think it is good to use function pointers here, they are good when you have to change the value of the pointer (the subroutine it points to) sometimes. Normal procedure arguments worked in FORTRAN77 and continue to work even now.


So as requested in the comment, if you are in a module and procedure with the right interface is accessible from the module (perhaps in the same module), you can use the procedure statement to get rod of the interface block:

module subs_mod
contains
  subroutine example_sub(aA, aB)
    integer,intent(...) :: aA, aB
    !the real example code
  end subroutine
end module

module action_mod
contains

  subroutine action(sub)
    use subs_mod
    procedure(example_sub) :: sub

    call sub(argA, argB)
  end subroutine
end module

but more likely, instead of a real subroutine you will create an abstract interface which you would reference with the procedure statement so in the end everything will be similar as before:

module action_mod

  abstract interface
    subroutine sub_interface(aA, aB)
      integer,intent(...) :: aA, aB
    end subroutine
  end interface

contains

  subroutine action(sub)
    procedure(sub_interface) :: sub

    call sub(argA, argB)
  end subroutine
end module

Upvotes: 17

Kiyomine
Kiyomine

Reputation: 33

I think use module to avoid interface is a good modern Fortran practice because it gives a cleaner interface.

Here is the ideal the realize that:

module part:

module foo
contains

subroutine callsub(sub,arg1,arg2)
!This subroutine is used to call other subroutines
external::sub !Use external to tell compiler this is indeed a subroutine
call sub(arg1,arg2)
end subroutine

subroutine sub(arg1,arg2)
!The subroutine to be called.
!do something
end sub

end module

Then here is the main program:

program main
use foo !Use module automatically avoids using interface.
implicit none
!Declare about args
call callsub(sub,arg1,arg2)
end program

Here is my demonstration to show exactly how this can be realized.

Upvotes: 2

Related Questions