calling function as argument 
Author Message
 calling function as argument

Hi all, sorry if this is a stupid question.
I am trying to build a subroutine that will call a function as its
argument (for integrating it for exemple) using the INTERFACE
statement in f90. I know how to do that in f77 using the EXTERNAL
statement, but I wanted to make it more general. Here is an exemple I
am trying to compile (using ifc 7.0) and the error message.
Any help is wellcome!
Thanks
Harry.

code:

MODULE MYMODULE
CONTAINS

SUBROUTINE Integrate(F,A,B,N)
REAL,INTENT(IN)::A,B
INTEGER,INTENT(IN)::N
REAL::DeltaX,X,Y,Sum
INTEGER::I

INTERFACE
  FUNCTION F(x)
  REAL::F
  REAL,INTENT(IN)::x
  END FUNCTION F
END INTERFACE

DeltaX = (B-A)/REAL(N)
X = A
Sum = 0.0

DO I=1,N-1
   X = X + DeltaX
   Y = F(X)
   Sum = Sum + Y
END DO
Sum = DeltaX*((F(A) + F(B))/2.0 + Sum)
WRITE(*,*) Sum

END SUBROUTINE Integrate

END MODULE MYMODULE

Program DefInt
USE MYMODULE
IMPLICIT NONE
REAL :: A,B
Integer :: Nu

READ *,A,B,Nu

call Integrate(Integrand,A,B,Nu)

CONTAINS

FUNCTION Integrand(x)
REAL::Integrand
REAL,INTENT(IN) :: X
Integrand = EXP(X**2)
END FUNCTION Integrand

END Program DefInt

Quote:
> ifc test.f90

   module MYMODULE
     module subroutine INTEGRATE
   program DEFINT
     internal function INTEGRAND
Error 277 : Another entity has the same name as internal procedure
INTEGRAND
Error 355 : In program unit DEFINT variable INTEGRAND has not been
given a type

2 Errors
compilation aborted for test.f90 (code 1)



Wed, 26 Oct 2005 03:03:52 GMT  
 calling function as argument
...

Quote:
> Program DefInt
> USE MYMODULE
> IMPLICIT NONE
> REAL :: A,B
> Integer :: Nu

> READ *,A,B,Nu

> call Integrate(Integrand,A,B,Nu)

> CONTAINS

> FUNCTION Integrand(x)
> REAL::Integrand
> REAL,INTENT(IN) :: X
> Integrand = EXP(X**2)
> END FUNCTION Integrand

> END Program DefInt

Internal procedures cannot be passed as arguments.  If the Integrand
function were an external, or a module procedure it would be fine.
I think the reason is that internal procedures were intended to be
always inlined or otherwise extremely well optimized.  So there
is not necessarily an entry point that can be independently passed
around.  That's only a guess.

--
J. Giles



Wed, 26 Oct 2005 03:30:42 GMT  
 calling function as argument

Quote:

> Hi all, sorry if this is a stupid question.

It isn't.

...

Quote:
> call Integrate(Integrand,A,B,Nu)

> CONTAINS

> FUNCTION Integrand(x)

....

The fundamental problem here is that you can't use an internal
procedure as an actual argument.  It must be an external or
module procedure.

I agree that the error message is "less than completely clear".
Hard to say exactly what the compiler is thinking is happening
here, but I think that's the actual problem.

I'll not go into all the arguments about why you can't do that.
For now, I'll just leave it with the fact that you can't.
It has been proposed to allow it and those proposals failed.

--
Richard Maine                       |  Good judgment comes from experience;
email: my first.last at org.domain  |  experience comes from bad judgment.
org: nasa, domain: gov              |        -- Mark Twain



Wed, 26 Oct 2005 03:34:36 GMT  
 calling function as argument

Quote:
> ...
> > call Integrate(Integrand,A,B,Nu)

> > CONTAINS

> > FUNCTION Integrand(x)
> ...

> The fundamental problem here is that you can't use an internal
> procedure as an actual argument.  It must be an external or
> module procedure.
> ...
> I'll not go into all the arguments about why you can't do that.
> For now, I'll just leave it with the fact that you can't.
> It has been proposed to allow it and those proposals failed.

Interestingly, CVF 6.6b allows that.  So, is it a bug or a feature?  I can
understand the requirement of an external procedure.  However, if an
internal function cannot be made accessible to other routines, why can a
module procedure?

--
Best Regards,
Greg Chien
e-mail: remove n.o.S.p.a.m.
http://protodesign-inc.com



Wed, 26 Oct 2005 04:00:38 GMT  
 calling function as argument

Quote:


> > The fundamental problem here is that you can't use an internal
> > procedure as an actual argument.
> Interestingly, CVF 6.6b allows that.  So, is it a bug or a feature?

It is an allowed extension.

Quote:
> I can
> understand the requirement of an external procedure.  However, if an
> internal function cannot be made accessible to other routines, why can a
> module procedure?

In short a module procedure cannot have a recursive host.  (The host
of a module procedure is just the module itself).  If you want the
long version, see the previous threads here.  A google search in
newsgroups on "internal procedure actual argument" gets plenty of
relevant hits (the first of which in the list I got was one of my
own postings of a year or so ago).

--
Richard Maine                       |  Good judgment comes from experience;
email: my first.last at org.domain  |  experience comes from bad judgment.
org: nasa, domain: gov              |        -- Mark Twain



Wed, 26 Oct 2005 04:20:53 GMT  
 calling function as argument

Quote:

> In short a module procedure cannot have a recursive host.  (The host
> of a module procedure is just the module itself).  If you want the
> long version, see the previous threads here.  A google search in
> newsgroups on "internal procedure actual argument" gets plenty of
> relevant hits (the first of which in the list I got was one of my
> own postings of a year or so ago).

Ah yes.  I had forgotten that reason.  Part of the nastiness of host
association.

--
J. Giles



Wed, 26 Oct 2005 04:37:25 GMT  
 calling function as argument

Quote:
> Interestingly, CVF 6.6b allows that.  So, is it a bug or a feature?  I can
> understand the requirement of an external procedure.  However, if an
> internal function cannot be made accessible to other routines, why can a
> module procedure?

The real complication is what to do when you pass in internal subprogram
of a recursive subprogram.  When the passed internal subprogram is
eventually invoked, which instance of the recursive host subprogram
shall be the active one?  In Note 12.12 the F95 standard recommends that
the correct instance is the one active when the internal subprogram was
passed.  If you think about the way fortran compilers typically pass
procedure dummy arguments as the address of the entry point, the question
arises as to how the callee is supposed to be informed as to which instance
to activate or even whether the actual argument it received is an internal
subprogram of a recursive subprogram in the first place.

Either you have to change the way procedure arguments or passed and invoked
for all procedure arguments or you have to get tricky with the offending
internal procedures when they are passed.  CVF takes the latter path and
assembles code in the stack frame of the recursive host when an instance
is created.  This code is merely a stub that sets up the stack frame pointer
to point to the stack frame of the current instance of the recursive host
and then jumps to the internal procedure.

There is, of course, another complication engendered by the CVF choice:
on most processors there is a significant performance penalty for using
the same memory locations as both code and data because it is more
difficult to maintain cache coherence for both instruction and data
caches.  If code and data lie in the same cache line that cache line
will be flushed from one cache when it is touched by the other cache on
many processors.  Thus, when you assemble code on the stack at run-time,
do you simply slop it into there and risk cache-throshing each time the
internal procedure is invoked, or do you put enough space around it in
the cache so that data can't lie on the same cache line as the self-
modified code?  Last time I checked, CVF packed everything tight in the
stack frame, saving space on the stack but risking cache thrashing.

Some people get the impression that invoking an internal procedure has
no overhead because there are no (or at least fewer) arguments to pass
because all (or most) of the information is communicated by host
association.  There is overhead, however, in communicating the data from
the host procedure and in fact, at least in older versions of CVF, I
have found that it was faster to pass everything as arguments rather
than via host association for one of those codes where everything was
recursive.

--
write(*,*) transfer((/17.392111325966148d0,3.6351694777236872d228, &
6.0134700169991705d-154/),(/'x'/)); end



Wed, 26 Oct 2005 04:58:32 GMT  
 calling function as argument

Quote:
> There is, of course, another complication engendered by the CVF choice:
> on most processors there is a significant performance penalty for using
> the same memory locations as both code and data because it is more
> difficult to maintain cache coherence for both instruction and data
> caches.  If code and data lie in the same cache line that cache line
> will be flushed from one cache when it is touched by the other cache on
> many processors.

I do think CVF could also choose to allocate a suitable block on the heap,
and put the stub code there. With the usual alignments of allocated blocks,
I suppose such false sharing wouldn't be a problem - certainly the problem
of sharing stack-local variables would go away.

        Jan



Sat, 29 Oct 2005 16:35:09 GMT  
 calling function as argument
On Tue, 13 May 2003 10:35:09 +0200, Jan C. Vorbrggen

Quote:

>I do think CVF could also choose to allocate a suitable block on the heap,
>and put the stub code there. With the usual alignments of allocated blocks,
>I suppose such false sharing wouldn't be a problem - certainly the problem
>of sharing stack-local variables would go away.

That's a lot more overhead for each call.  I suspect the cost would
outweigh the benefits.  You'd also have to add deallocate code at all
exit points.


Steve Lionel
Software Products Division
Intel Corporation
Nashua, NH

User communities for Intel Fortran and Compaq Visual Fortran:
  http://intel.com/IDS/community



Sat, 29 Oct 2005 21:17:33 GMT  
 
 [ 9 post ] 

 Relevant Pages 

1. Calling function with arguments

2. VC++ calling fortran function and fortran function calling a c++ function

3. Calling dll functions which need pointers to be passed as an argument

4. Rest of arguments in a function call

5. function has been called with too many arguments

6. Calling a python function with a list as the input argument from C

7. problem calling functions with default arguments

8. Call a function in DLL with string arguments?

9. Calling a function, arguments in a dict ??

10. Multiple arguments, structured arguments [ LONG ] (was Re: dyadic functions)

11. passing functions with variable number of arguments as procedure arguments

12. How to find out name of calling function from called function

 

 
Powered by phpBB® Forum Software