Search code examples
staticfortran

fortran access routine inside "contains" statement in separate routine


I am trying to reset the save variable inside a routine, a way I theorize going around this is having a reset() function that zeros out the data inside, however I cannot directly call this function as it is inside the "contains" keyword, is there a way to override this protection? I've looked into "interface" and "external" keywords but the documentation for this particular question seems sparce

program main
   implicit none

   call count ! 1
   call count ! 2
   call count ! 3

   ! cannot make a call to reset
   ! is there any way to remove this
   ! protection and access this directly?
   call reset
   call count ! 1 etc...
end program main

subroutine count
   integer, save :: numcalled = 0

   numcalled = numcalled + 1
   print *, numcalled

   return
contains

   subroutine reset
      numcalled = 0
   end subroutine reset
end subroutine count

This is a small example to get the idea of what I aim to do to a project with a bunch of "save" variables and I need to reset these as this code will be called several times and stuff needs to be fresh for each function call (no static variables floating around with bad state), if I can override this protection to access subroutines inside a "contains" keyword this would be a very minimally invasive task


Solution

  • The procedure declared after contains is an internal procedure. It cannot be called from the outside world. There is no way.

    You would have to store the data in a module and have a reset module procedure

    module subs
        implicit none
    
        integer, save :: numcalled = 0
    
    contains
    
      subroutine count
       
    
        numcalled = numcalled + 1
        print *, numcalled
    
      end subroutine count
    
      subroutine reset
          numcalled = 0
      end subroutine reset
    end module
    

    or have a special argument to your count subroutine to tell it it should call its reset function for you.

    subroutine count(do_reset)
       integer, save :: numcalled = 0
       logical :: do_reset
    
       if (do_reset) call reset
    
       numcalled = numcalled + 1
       print *, numcalled
    
       return
    contains
    
       subroutine reset
          numcalled = 0
       end subroutine reset
    end subroutine count
    

    You can make the argument optional. You can also return from the subroutine after calling reset without executing the rest of the code.

    Anyway, no matter what solution you choose, all procedures should be in modules if there is no specific reason against.