Search code examples
fortransubroutine

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.


Solution

  • 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