1

I understand the interface command can be used to pass a a function into a subroutine. So for example in the main program I'd define some function and then pass it to some subroutine like:

MainProgran

Use ....

Implicit None

Type decorations etc

Interface
   Function test(x,y)
   REAL, INTENT(IN) :: x, y
   REAL :: test
   END function
End Interface

   Call Subroutine( limit1, limit2, test, Ans)


End MainProgram

Is this the correct way of doing this? I'm quite stuck! Also within the Subroutine is there anything I need to put to let it know that a function is coming in? The Subroutine in this case will be a library so I don't want to have to keep recompiling it to change the function.

user2350366
  • 491
  • 1
  • 4
  • 20
  • 2
    Where test comes from? How does the Subroutine look like? The interface placed there may serve for more purposes, but it is quite possibly not necessary for just passing the test in this case. You should find a minimal self-contained compilable piece of code. – Vladimir F Героям слава Mar 06 '14 at 12:56
  • 2
    relevant http://stackoverflow.com/questions/15926727/passing-function-to-subroutine-in-fortran – agentp Mar 06 '14 at 13:06
  • 4
    Hint: put the interface block into the subroutine to declare the dummy argument of the the subroutine that will receive the function. Then the subroutine knows the properties of the functions that it will receive. It doesn't have to be recompiled to receive different functions. – M. S. B. Mar 06 '14 at 15:44

3 Answers3

0

A simple way to do this is to go old school and just leave the function external:

 program main
 real f,z
 external f
 call subr(f,z)
 write(*,*)z
 end

 real function f(x)
 real x
 f=x**2
 end

! below possibly in a precompiled library:

 subroutine subr(f,y)
 real f,y
 y=f(2.)
 end

out: 4

Of course with this approach you can not use advanced language features that require an explicit interface. **

On the other hand if you are interfacing with standard libraries that need function arguments this is I think the only way.

** per MSB's comment you can handle that issue with an interface block in the subroutine, for example if we want to pass a function that returns an array:

 function f(x)
 real x,f(2)
 f(1)=x
 f(2)=x**2
 end

as in the first example f is an external function, and the sub can be in a precompiled library:

 subroutine subr(g,y)
 interface
 function g(x)
 real x,g(2)
 end function
 end interface
 real y,z(2)
 z=g(2.)
 y=z(1)+z(2)
 end

out: 6

As noted, this is only strictly necessary if relying on language features that need the interface.

agentp
  • 6,849
  • 2
  • 19
  • 37
0

Module:

module fmod
    interface
       function f_interf(x,y)
       real, intent(in) :: x, y
       real :: f_interf
       end function
    end interface

contains 
    function f_sum(x,y)
    real, intent(in) :: x, y
    real f_sum

    f_sum = x + y

    end function

    function f_subst(x,y)
    real, intent(in) :: x, y
    real f_subst

    f_subst = x - y

    end function

    subroutine subr(limit1, limit2, func, ans)
    real limit1, limit2
    procedure(f_interf) func
    real ans

    ans = func(limit1, limit2)
    end subroutine
end module

main program:

program pass_func
use fmod
Implicit None
real ans, limit1, limit2
limit1 = 1.0
limit2 = 2.0
call subr( limit1, limit2, f_subst, ans)
write(*,*) ans
call subr( limit1, limit2, f_sum, ans)
write(*,*) ans
end program pass_func

and output:

  -1.000000
   3.000000
Peter Petrik
  • 9,701
  • 5
  • 41
  • 65
0

The most elegant way I know of right now is to put your functions into a module so that you don't have to do construct interface but simply use 'external'. Here is a example to do that.

It covers different situations using subroutine or function as arguments for subroutine or function.

Notice if you want to pass array as argument without receiving null arraies, here is a tip to do that.

Module part:

module func_arg_test
!I used ifort to compile but other compilers should also be fine.
!Written by Kee
!Feb 20, 2017
contains

!-------------------------
real function func_func(f, arg)
!========================================
!This shows how to pass number as argument
!========================================
implicit none
real, external::f !Use external to indicate the f is a name of a function
real::arg

func_func=f(arg)
end function func_func

real function func_sub(subr, arg)
!========================================
!This shows how to pass subroutine as arg to function
!========================================
implicit none
external::subr !Use external to indicate subr is a subroutine
real::arg

call sub(arg)
func_sub = arg
end function func_sub


subroutine sub_func(f,arg)
!========================================
!This shows how to pass function as argument
!in subroutine 
!========================================
real::arg
real,external::f
arg = f(arg)
end subroutine sub_func

subroutine sub_sub(subr,arg)
!========================================
!This shows how to pass subroutine as argument
!in subroutine 
!========================================
real::arg
external::subr
call subr(arg)
end subroutine sub_sub




real function funcmat(f, mat)
!========================================
!This shows how to pass matrix as argument
!========================================
implicit none
real, external::f
real,dimension(:)::mat!Here memory for mat is already allocated when mat is
!passed in, so don't need specific size
integer::sizeinfo
sizeinfo = size(mat)
funcmat = f(mat,sizeinfo)
end function funcmat
!--------------------------

real function f1(arg)
!This test function double the number arg
implicit none
real::arg
f1 = arg*2
return
end function f1

real function f2(arg)
!This test function square the number arg
implicit none
real::arg
f2 = arg*arg
return
end function f2

real function fmat(mat,sizeinfo)
!This test function sum up all elements in the mat
implicit none
integer::sizeinfo!This is the method I come up with to get around the
!restriction.
real,dimension(sizeinfo)::mat!This mat cannot be undetermined, otherwise it
!won't recevie mat correctly. I don't know why yet.
fmat = sum(mat)
end function fmat

subroutine sub(arg)
real::arg
arg = arg*3
end subroutine sub
end module

Main program:

program main
use func_arg_test
implicit none
real::a = 5d0
real::output
real, dimension(:),allocatable::mat

write(*,*) 'value of a=',a
output = func_func(f1,a)
write(*,*) 'a is  doubled'
write(*,*) output
output = func_func(f2,a)
write(*,*) 'a is squared'
write(*,*) output
output = func_sub(sub,a)
write(*,*) 'a is tripled and overwritten'
write(*,*) output
call sub_func(f2,a)
write(*,*) 'a is squared and overwritten'
write(*,*) a
call sub_sub(sub,a)
write(*,*) 'a is tripled and overwritten'
write(*,*) a

allocate(mat(3))
mat = (/1d0,10d0,1d0/)!The allocatable arrray has to have a determined shape before
!pass as arguemnt
write(*,*) '1D matrix:',mat
write(*,*) 'Summation of the matrix:'
output = funcmat(fmat,mat)!elements of mat are summed
write(*,*) output

end program

And the result is:

value of a=   5.000000    
 a is  doubled
   10.00000    
 a is squared
   25.00000    
 a is tripled and overwritten
   15.00000    
 a is squared and overwritten
   225.0000    
 a is tripled and overwritten
   675.0000    
 1D matrix:   1.000000       10.00000       1.000000    
 Summation of the matrix:
   12.00000    

 
Community
  • 1
  • 1
Kiyomine
  • 33
  • 5
  • No, `external` is not most elegant. It is old, obsolete and error-prone becauase the procedure that receives the procedure argument then does not have *explicit interface* to the passed procedure and the correctness cannot be checked. – Vladimir F Героям слава Feb 21 '17 at 06:34