0

I would like to use a variable subroutine name, and I would like this name to be available throughout a module, not just in a single subroutine.

A variable subroutine name passed as an argument is a type of data. Where is it stored? How can I access it?

Here is more explanation. G is a nonlinear fitting routine. H uses G but with grouping of parameters (iteration moving one group at a time). G uses a general forward model subroutine whose name is passed as an argument. I would like H to preserve this generality.

Here is the test program using a workaround with a hardcoded subroutine name:

  module G_MOD
  implicit none
  character(len=30)::message='Good Morning'

  contains

  subroutine G(Sub)
  external::Sub
  call Sub
  end subroutine G

  end module G_MOD

  module H_MOD
  use G_MOD
  implicit none

  contains

  subroutine H(sub)
  external:: sub
  call G(LocalSub)
  end subroutine H

  subroutine LocalSub
  external:: MySub
  message='Good Afternoon'
  call G(MySub) ! the subroutine name "MySub" is hardcoded
                ! I would like it to be argument sub
  end subroutine LocalSub

  end module H_MOD

  program test
  use H_MOD
  implicit none
  external MySub
  call H(MySub)
  end program test

  subroutine MySub
  use G_MOD,only:message
  write(*,*)trim(Message)
  end subroutine MySub
3

1 Answer 1

1

Solution 1

You don't need to store anything if you make LocalSub internal to H:

  subroutine H(sub)
    external:: sub
    call G(LocalSub)
  contains
    subroutine LocalSub
      message='Good Afternoon'
      call G(sub)
    end subroutine LocalSub
  end subroutine H

It requires Fortran 2008.

With some cleanup, indentation for readability, removing the ugly externals using an abstract interface (Fortran 2003, but external can be avoided even in Fortran 90 using interface blocks) the code is:

  module G_MOD
    implicit none
    character(len=30)::message='Good Morning'

    abstract interface
      subroutine sub_interface
      end subroutine
    end interface

  contains

    subroutine G(Sub)
      procedure(sub_interface) :: sub
      call Sub
    end subroutine G

  end module G_MOD

  module H_MOD
    use G_MOD
    implicit none

  contains

    subroutine H(sub)
      procedure(sub_interface) :: sub
      call G(LocalSub)
    contains
      subroutine LocalSub

        message='Good Afternoon'
        call G(sub) 
      end subroutine LocalSub
    end subroutine H

  end module H_MOD

  program test
    use H_MOD
    implicit none


    call H(MySub)
  contains
    subroutine MySub
      use G_MOD,only:message
      write(*,*)trim(Message)
    end subroutine MySub
  end program test

Solution 2

If you really want to store a reference to the procedure in a module, it is possible, but remember global variables are UGLY. What if you want to make multiple calls to your optimization in parallel?

So, you can store the address (not name) of a procedure in a procedure pointer. These require Fortran 2003. A minimal change of your code is

  module H_MOD
    use G_MOD
    implicit none

    procedure, pointer :: stored_sub => null()

  contains

    subroutine H(sub)
      external:: sub
      stored_sub => sub
      call G(LocalSub)
    end subroutine H

    subroutine LocalSub
      message='Good Afternoon'
      call G(stored_sub)
    end subroutine LocalSub

  end module H_MOD

but much better modern code is:

  module G_MOD
    implicit none
    character(len=30)::message='Good Morning'

    abstract interface
      subroutine sub_interface
      end subroutine
    end interface

  contains

    subroutine G(Sub)
      procedure(sub_interface) :: sub
      call Sub
    end subroutine G

  end module G_MOD

  module H_MOD
    use G_MOD
    implicit none

    procedure(sub_interface), pointer :: stored_sub => null()

  contains

    subroutine H(sub)
      procedure(sub_interface) :: sub
      stored_sub => sub
      call G(LocalSub)

    end subroutine H

    subroutine LocalSub

      message='Good Afternoon'
      call G(stored_sub) 
    end subroutine LocalSub

  end module H_MOD


  module MySub_module
  contains
    subroutine MySub
      use G_MOD,only:message
      write(*,*)trim(Message)
    end subroutine MySub
  end module MySub_module

  program test
    use H_MOD
    use MySub_module
    implicit none


    call H(MySub)
  end program test

Still, I definitely prefer the variant with the internal procedure.

And remember, use indentation, it is essential for readable code.

Sign up to request clarification or add additional context in comments.

3 Comments

what happens if you modify it?
The modification is question is to add the line call stored_sub before the line call G(stored_sub). This should function the same and result in two "Good Afternoon" messages. However it causes the compile to fail with G95 but not with Intel (In file solution2.for:36 call stored_sub 1 Error: Symbol 'stored_sub' at (1) has no IMPLICIT type.
Some bug in G95. Forget G95, it is old and no longer supported. Use gfortran instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.