Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

circular calling

rahzan
Novice
580 Views
if I call a USEd module the child and the USEr module the parent. Is the a trick to provide the child function access to the generic functions in the parent?

In a simple setup of main and a subroutine (not contained), the subsoutine seems the "exportable" to a procedure in a USEd module via the external specification. i.e. this works:

module y
contains
subroutine sub(x,func)
integer,external:: func
real:: x
write(*,*)x,func(2)
pause
end subroutine sub
end module y

use y
external func
x=1.
call sub(x,func)
end
integer function func(i)
func=i*2
end function


But it seems that a module procedure cannot do the same with another procedure in its own module to export to a procedure in another module, e.g.
module y
contains
subroutine sub(x,func)
integer,external:: func
real:: x
write(*,*)x,func(x)
pause
end subroutine sub
end module y

module z
use y
real dat
external func
contains

subroutine setdat(x)
dat=x
end subroutine

real function func
func=dat*r
end function

subroutine subz(x)
real x
call sub(x,func)
end subroutine

end module z

use z
call setdat(2.14)
call subz(2.)
end

Is there a way to get this to work, somehow?
Is there a good reason for this difference?

Thanks, Tim
0 Kudos
5 Replies
Steven_L_Intel1
Employee
580 Views
Forget EXTERNAL - you can leave it behind when you enter the world of Fortran 90. The problem here is that in module Y, your EXTERNAL declaration of FUNC refers to something outside (external to) the module, but you then proceed to declare a module procedure FUNC.

The solution is to use an INTERFACE block to declare the routine argument to SUB. Now FUNC matches that interface.

module y
contains
subroutine sub(x,func)
interface
  real function func
    real r
    end function func
  end interface
real:: x
write(*,*)x,func(x)
pause
end subroutine sub
end module y

module z
use y
real dat
contains

subroutine setdat(x)
dat=x
end subroutine

real function func
func=dat*r
end function

subroutine subz(x)
real x
call sub(x,func)
end subroutine

end module z

use z
call setdat(2.14)
call subz(2.)
end


Steve
0 Kudos
rahzan
Novice
580 Views
At the risk of insolence, your version works fine!

However, my problem lies in a lack of general understanding of the Interface block. Despite the fact I have used in MANY occasions, I use it like I write c programs, just follow the recipe without a real understanding!

In this case, how does the interface (or shall I ask what property of the interface) tells the subroutine sub(x,func), as to where exactly to find func?

Thanks, Tim

Tim H
0 Kudos
Jugoslav_Dujic
Valued Contributor II
580 Views
EXTERNAL and INTERFACE are actually interchangeable in most contexts (of course, INTERFACE carries much more information which can be used for typechecking). Read on...

Perhaps the easiest way is to explain it from compiler's/linker's viewpoint. At the end of the process, they have to know addresses of every entity to be able to refer to them. Fortran has no "file-scope" concept, but every routine is world for itself. In F77, there were no modules, and there are no means (other than EXTERNAL) that the routines "know" about each other's existence and prototype. Compiler "deduces" what a name is based on the context (Does it have a CALL in front? -- it's a SUBROUTINE. Is it part of an expression -- it's a FUNCTION. Do I see its declaration? -- it's a variable).

Thus, in F77, if you have to pass func around, if you write:
PROGRAM Proggie
CALL sub(1.,func)
END
!----
INTEGER FUNCTION Func(x)
...
END
When compiling Proggie, compiler doesn't know about existence of function Func -- it would instantiate a REAL variable func and pass it, which is not what you want. So, you have to tell it that Func is actually an EXTERNAL (which goes to your sample above).

Now, in F90, routines are able to "know about each other" () by means of:
- USE association (Proggie USEs the module containing Func)
- Host association (Func is CONTAINed within Proggie, or both Proggie and Func are CONTAINed within the same module -- [the latter is not allowed if Proggie is a PROGRAM, but it is if it's a SUBROUTINE or FUNCTION])
- INTERFACE blocks
- EXTERNAL attribute, as in F77.

The first 3 means are called "explicit interface" by one
name. Now, if 2 routines know about each other by means of use or host association, it is not allowed to redeclare the association using INTERFACE or EXTERNAL.

In this case, how does the interface (or shall I ask what property of the interface) tells the subroutine sub(x,func), as to where exactly to find func?

The key point that Steve made is not that he introduced the INTERFACE within Sub (as I said above, INTEGER, EXTERNAL:: would work as well). The key point is that he DELETED the "EXTERNAL Func" line from module z.
Why? SUBZ and FUNC are already host-associated and "know" about each other. When you added "EXTERNAL Func" to Z, you confused the compiler: "Oh, wait, Subz already knows what Func is, but now you're telling me that Func is something from outer world? What the heck it is???". (I'm not sure if you got compiler or linker error).

Now, in "pure" F90-style (everything in MODULEs) there's almost no need for INTERFACEs/EXTERNALs. Since all routines "know" about each other, compiler can get everything right. The exception to this is when a routine is a dummy (formal) argument -- as your Func to Sub. In that case, you have to tell the compiler what it is, since it can't resolve the reference at compile-time, because it gets the value from the actual argument. As I said, Steve's INTERFACE allows better typechecking, but INTEGER, EXTERNAL:: would serve as well.

Is it clearer now?

Jugoslav
0 Kudos
rahzan
Novice
580 Views
Thanks,
It is just the way I had suspected it.
But you make it sound as if interface is a new feature in f90. But I remember it from years ago. Anyway let's not get into that too much, unless there is a good reason!!

Anyway, first a comment and then a quickie:
So is it reasonable to say that Interface is a way for letting the compiler know about routines which are not defined not just at compile time but also-- in the case of libraries (e.g. libs, modules, dll's)-- all the way though the link time as well.

If this is true, I'd like to know why in steve's version is it necessary to not only declare the interface but ALSO pass the name FUNC in the arg list? isn't the interface saying enough? (assuming my statment aboveis correct.)

thanks for your time.
Tim
0 Kudos
Jugoslav_Dujic
Valued Contributor II
580 Views
But you make it sound as if interface is a new feature in f90. But I remember it from years ago. Anyway let's not get into that too much, unless there is a good reason!!

It existed as a F77 extension, and I remember it as well from MS 5.1, but it had somewhat different syntax than F90 standard version.

So is it reasonable to say that Interface is a way for letting the compiler know about routines which are not defined not just at compile time but also-- in the case of libraries (e.g. libs, modules, dll's)-- all the way though the link time as well.

Since I didn't understand what you said, I'd guess that the answer is "no, it isn't reasonable to say so" ;-).
Certainly, you need INTERFACEs for dummy arguments; you'd also need them in cases like mixed-language programming, where routines from other language cannot be use- or host- associated.

If this is true, I'd like to know why in steve's version is it necessary to not only declare the interface but ALSO pass the name FUNC in the arg list? isn't the interface saying enough? (assuming my statment aboveis correct.)

The big difference is that Func in Sub is a dummy argument name. In this case, Interface describes that Func is a real function with one real argument, in a similar manner that X is a real scalar. Instead of "Func", there might have stood anything, since it's just a dummy argument -- replace all occurrences of "Func" in sub with "Foo" and it's still perfectly fine.

Further, y::Sub is not use- or host- associated with z::Func in any way, so it doesn't "know" about it and an Interface won't help, since the only way to call a routine from a module is to USE that module*.

Jugoslav
-----
*) You could overcome that by cheating, using !DEC$ATTRIBUTES ALIAS. Note that you could ALIAS and DLLEXPORT a module procedure, and call it from e.g. VB, so you could call it from another CVF program. But that's just cludging.
0 Kudos
Reply