Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CONTAINS problem

136 views
Skip to first unread message

Dieter Britz

unread,
Oct 2, 2012, 4:07:40 AM10/2/12
to
I want to have a function in a CONTAINS section within a subroutine.
E.g.

subroutine SUB (...)
implicit none
...
CONTAINS
function FUNC (...)
...
end function FUNC
end subroutine SUB

The function is of type real. My problem is,
how and where to declare it. If I declare it as
real :: FUNC
in the subroutine, I am told in the function that
the FUNC declaration is missing, but if I put it in,
then I am told that it's already been declared.

How is it done properly?
--
Dieter Britz

simon

unread,
Oct 2, 2012, 4:13:19 AM10/2/12
to
contains
function FUNC (...)
real(4) :: FUNC
...
end function FUNC
end subroutine SUB


Simon

Robin Vowels

unread,
Oct 2, 2012, 5:10:43 AM10/2/12
to
That's not portable.

real :: FUNC
is sufficient.
For double precision, use either
DOUBLE PRECISION :: FUNC
or
real (kind=kind(1.0d0)) :: FUNC
or
real (dp) :: FUNC
with dp suitably defined,
or somesuch.

Arjen Markus

unread,
Oct 2, 2012, 5:52:26 AM10/2/12
to
Such an internal function works in much the same way as functions in
a module. The exception is that it can not be used outside the context of
the containing program unit.

Regards,

Arjen

glen herrmannsfeldt

unread,
Oct 2, 2012, 9:01:29 AM10/2/12
to
What is the actual message that you get with no

real:: FUNC

statement? The function itself should be enough to declare
the function.

Do note that inside the function, FUNC is a variable, not
a function. Is that confusing you?

-- glen

simon

unread,
Oct 2, 2012, 9:19:47 AM10/2/12
to
True, but it does depend on the world you inhabit. In the world of 32
and 64 bit Windows with the Intel Fortran compiler and tens of thousands
of lines of code it is portable. Another option for absolute portability is

function FUNC(...)
use iso_fortran_env
real(real32) :: FUNC
...
end function FUNC

but then, of course, the compiler has to support F2008 so perhaps it's
not (yet) that portable.

Simon


Richard Maine

unread,
Oct 2, 2012, 10:41:33 AM10/2/12
to
simon <si...@whiteowl.co.uk> wrote:

> On 02/10/2012 10:10, Robin Vowels wrote:
> > On Oct 2, 6:13 pm, simon <si...@whiteowl.co.uk> wrote:
...
> >> real(4) :: FUNC
> >
> > That's not portable.
...
> True, but it does depend on the world you inhabit. In the world of 32
> and 64 bit Windows with the Intel Fortran compiler and tens of thousands
> of lines of code it is portable. Another option for absolute portability is

Odd definition of portability - that it is "portable" to a specific
compiler. Usually "portable" refers to porting between multiple things.
There can be reasons for restricting oneself to a particular compiler,
but we don't normally call that "portable"; we just say that the
particular code doesn't require portability for whatever reason.

Admitedly, that particular form is actually portable to more than just
that compiler. It is not, however, portable to some other widely used
compilers, even in the world of 32- and 64-bit Windows.

> Another option for absolute portability is
...
> use iso_fortran_env
> real(real32) :: FUNC
...
> but then, of course, the compiler has to support F2008 so perhaps it's
>not (yet) that portable.

You omitted the widely-recommended way that has been portable since F90
first introduced kinds. Write your own module to define your own
parameter using selected_real_kind. Or, if selected_real_kind is just to
verbose for you or there are other reasons, just define your parameter
with the hard-wired value of 4. But at least if you hard-wire that
value, do so in such a module so that it only needs to be changed in one
place.

The standardized parameters introduced in f2008 are handy, I agree. They
are nice shorthand for the most common cases, and easier to explain than
selected_real_kind. In fact, if I recall correctly, I had pushed to have
something like them in f2003. But they are mostly just nice shorthand.
Selected_real_kind is in the standard and works with *ALL* f90 and later
compilers on all machines.

Strewing real(4) declarations all over a large code is asking for it.
Yes, I *HAVE* seen people who had porting difficulties because they have
done that. Sure, there are other people who have not happened to run
into problems. But when giving advice to 3rd parties, I don't think it
wise to give them advice based on what just happened to work for your
environment without at least mentioing the caveat. They will go away not
knowing that the caveat exists and then get in trouble because they
think their code is portable to all compilers. Yes, I have seen people
get that misimpression and get in trouble as a result. Examples have
appeared in this newsgroup.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain

Robin Vowels

unread,
Oct 2, 2012, 10:42:20 AM10/2/12
to
On Oct 2, 11:01 pm, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
> Dieter Britz <dieterhansbr...@gmail.com> wrote:
> > I want to have a function in a CONTAINS section within a subroutine.
> > E.g.
> > subroutine SUB (...)
> >  implicit none
> > ...
> > CONTAINS
> > function FUNC (...)
> > ...
> > end function FUNC
> > end subroutine SUB
> > The function is of type real. My problem is,
> > how and where to declare it. If I declare it as
> > real :: FUNC
> > in the subroutine, I am told in the function that
> > the FUNC declaration is missing, but if I put it in,
> > then I am told that it's already been declared.
>
> What is the actual message that you get with no
>
> real:: FUNC
>
> statement? The function itself should be enough to declare
> the function.

No it isn't. He's using IMPLICIT NONE, and that requires an
explicit declaration of FUNC.

Robin Vowels

unread,
Oct 2, 2012, 10:47:24 AM10/2/12
to
There are more compilers than Intel. And there are more operating
systems than Windows.

So, when advising someone on how to write a declaration,
it's best to give something that's portable,
and the simplest is real :: FUNC

Below is not particularly portable at the present time.

Richard Maine

unread,
Oct 2, 2012, 11:06:29 AM10/2/12
to
As usual, I recommend posting complete actual code instead of just a
sample. Descriptions like the above so often miss the critical parts. On
a second reading, I think I was able to infer the critical part in this
case, but that's not always so, and it did take a second reading. In
particular, I noticed that you talked about a declaration in the
subroutine, but omitted any mention of one in the function.

Just like any other function. You *ALWAYS* (well, almost always) declare
the type of the function within the function itself. That is true
whether the function is an external, module, or internal function. (The
exception is statement functions, because they don't have an inside for
the declaration to be in, but statement functions break so many rules
that I consider it best to forget them, as I almost did in writing
"always" above).

For an external function (ok, or a statement function), you also need to
declare it for the calling procedure, either in the calling procedure,
in its host, or in a module that it uses. But that's an also; it does
not replace (except for the statement function case) the declaration in
the function itself.

For an internal or module function, there is automatically an explicit
interface and you are not allowed to redeclare the function in the
calling scope.

To folllow my own advice (something I'm afraid I don't always do :-(),
I'll give an actual compilable sample instead of just describing it.
I took your code, removed the ellipses (and the then-empty parens from
the subroutine statement), and added the declaration in the function,
giving a complete compilable sample

subroutine SUB
implicit none
CONTAINS
function FUNC ()
real :: func
end function FUNC
end subroutine SUB

Compiled fine with the gfortran on this machine.

Simon Geard

unread,
Oct 2, 2012, 3:17:32 PM10/2/12
to
On 02/10/12 15:41, Richard Maine wrote:
> simon<si...@whiteowl.co.uk> wrote:
>
>> On 02/10/2012 10:10, Robin Vowels wrote:
>>> On Oct 2, 6:13 pm, simon<si...@whiteowl.co.uk> wrote:
> ...
>>>> real(4) :: FUNC
>>>
>>> That's not portable.
> ...
>> True, but it does depend on the world you inhabit. In the world of 32
>> and 64 bit Windows with the Intel Fortran compiler and tens of thousands
>> of lines of code it is portable. Another option for absolute portability is
>
> Odd definition of portability - that it is "portable" to a specific
> compiler. Usually "portable" refers to porting between multiple things.
> There can be reasons for restricting oneself to a particular compiler,
> but we don't normally call that "portable"; we just say that the
> particular code doesn't require portability for whatever reason.
>
Well I've re-read what I wrote and I can't find anywhere that this is my
definition of portability. I could have listed all the machines which in
my experience have had real(4) declared the same size variable but
didn't think it was necessary since it was not germane to the OPs
question. I suppose for completeness I should state that my experience
is limited to Linux with Intel and gfortran (which, btw, supports
iso_fortran_env) and native compilers on Solaris, HP-UX, Irix, SunOS,
IBM 370. In all of these the code with real(4) worked and so by that
measure it is a portable declaration. There are others (Apollo, Prime
(Salford F77 compiler), ICL 1904s, ICL Perq, AIX and VAX workstations)
which I've worked on but cannot remember whether or not real(4) behaved
as expected.

That there are environments in which real(4) does not declare the same
size variable I don't doubt, I just wouldn't like it to be thought that
my only experience is with M$ Win.

> Admitedly, that particular form is actually portable to more than just
> that compiler. It is not, however, portable to some other widely used
> compilers, even in the world of 32- and 64-bit Windows.
>


>> Another option for absolute portability is
> ...
> > use iso_fortran_env
> > real(real32) :: FUNC
> ...
>> but then, of course, the compiler has to support F2008 so perhaps it's
>> not (yet) that portable.
>
> You omitted the widely-recommended way that has been portable since F90
> first introduced kinds. Write your own module to define your own
> parameter using selected_real_kind. Or, if selected_real_kind is just to
> verbose for you or there are other reasons, just define your parameter
> with the hard-wired value of 4. But at least if you hard-wire that
> value, do so in such a module so that it only needs to be changed in one
> place.
>
My experience of the hundreds of thousands of lines of Fortran I've
worked on professionally since 1985 on the above machines is that no one
has ever used the 'widely recommended way'. Not once. Where it is are
used is in c-callable code (using iso_c_binding).

> The standardized parameters introduced in f2008 are handy, I agree. They
> are nice shorthand for the most common cases, and easier to explain than
> selected_real_kind. In fact, if I recall correctly, I had pushed to have
> something like them in f2003. But they are mostly just nice shorthand.
> Selected_real_kind is in the standard and works with *ALL* f90 and later
> compilers on all machines.

>
> Strewing real(4) declarations all over a large code is asking for it.
> Yes, I *HAVE* seen people who had porting difficulties because they have
> done that. Sure, there are other people who have not happened to run
> into problems.
I believe you. I too have had many porting difficulties over the years
as well, but real(4) has never been one of them.

But when giving advice to 3rd parties, I don't think it
> wise to give them advice based on what just happened to work for your
> environment without at least mentioning the caveat. They will go away not
> knowing that the caveat exists and then get in trouble because they
> think their code is portable to all compilers. Yes, I have seen people
> get that misimpression and get in trouble as a result. Examples have
> appeared in this newsgroup.
>
I agree, I should have just kept it simple and not (inadvertently)
redirected this thread.

Simon



Simon Geard

unread,
Oct 2, 2012, 3:17:35 PM10/2/12
to
Again true (rather self-evidently don't you think). It is the curse of
the newsgroup format that there is forever a trade-off between brevity
and precision. In my attempt to keep things simple for the OP I seemed
to have mislead you and some others into thinking that what I described
is my only experience of Fortran and that somehow I was making a
completely unjustified assumption about portability; I simply kept it to
the particular environment in which I'm working at the moment.

See my reply to Richard's post for information.
>
> So, when advising someone on how to write a declaration,
> it's best to give something that's portable,
> and the simplest is real :: FUNC

I agree. I was erroneously conflating my current work requirements with
simplicity for the OP. I will try to do better in future.


Simon

Gordon Sande

unread,
Oct 2, 2012, 4:18:52 PM10/2/12
to
NAGWare Fortran uses a default of sequential numbering of the types.
NAG is interesting as
1. they were an early vendor (earliest F90 if I am correct), 2. they
have some of the best
debugging support avaialable and 3. they support a wide range of
systems. If NAG is
not in the supported collection it is a bit hard to claim serious
"portability".

> That there are environments in which real(4) does not declare the same
> size variable I don't doubt, I just wouldn't like it to be thought that
> my only experience is with M$ Win.

Before the era of commodity 32 bits chips there were major vendors
offering 36 bit, 48 bit
and 60 bit machines. Byte has not always been very well defined and
could mean 6, 7 or 8
bits. There have even been major vendors who offered machines with
differing floating point
formats within the same word size.

Tobias Burnus

unread,
Oct 2, 2012, 4:36:58 PM10/2/12
to
Gordon Sande wrote:
>
> NAGWare Fortran uses a default of sequential numbering of the types. NAG
> is interesting as
> 1. they were an early vendor (earliest F90 if I am correct), 2. they
> have some of the best
> debugging support avaialable and 3. they support a wide range of
> systems. If NAG is
> not in the supported collection it is a bit hard to claim serious
> "portability".

Well, NAG also supports REAL*4 by default and REAL(4) using the
command-line option -kind=byte; thus, they also saw the need to support
those kind of kind numbers.

The wide platform support is probably not surprising, given that they
generate C code which is automatically compiled using the system's C
compiler.

Otherwise, I concur that NAG is probably the best compiler if one wants
to have a compiler which has very good compile- and run-time diagnostic
and nearly fully supports Fortran 2003. (A disadvantage - for code users
not developers - is that it lacks common vendor extensions.)

And regarding the kind numbers: I think they are quite useful, even
though I usually end up writing "integer, parameter :: dp = kind(0.0d0)".

Tobias

John Harper

unread,
Oct 2, 2012, 5:02:54 PM10/2/12
to
Richard Maine wrote:

> Dieter Britz <dieterh...@gmail.com> wrote:
>
>> I want to have a function in a CONTAINS section within a subroutine.
>> E.g.
>>
>> subroutine SUB (...)
>> implicit none
>> ...
>> CONTAINS
>> function FUNC (...)
>> ...
>> end function FUNC
>> end subroutine SUB
...

> As usual, I recommend posting complete actual code instead of just a
> sample. Descriptions like the above so often miss the critical parts. On
> a second reading, I think I was able to infer the critical part in this
> case, but that's not always so, and it did take a second reading.

One critical part that the OP didn't supply and Richard didn't expound is
that internal subprograms may appear in external subprograms like Richard's
above, in module subprograms, or in main programs, but they shall not appear
in other internal subprograms. Those rules were in F90 12.1.2.2 and they are
still there in F2008 12.2.2.2.

--
John Harper

James Van Buskirk

unread,
Oct 2, 2012, 4:39:56 PM10/2/12
to
"Arjen Markus" <arjen.m...@gmail.com> wrote in message
news:6adbe8dc-e0ab-4510...@googlegroups.com...

> Such an internal function works in much the same way as functions in
> a module. The exception is that it can not be used outside the context of
> the containing program unit.

The function can be invoked from program units other than the host
or its sibling internal procedures in f2008, by pointing a Fortran
procedure pointer at it or taking its C_FUNLOC and passing one of
those or the function itself as an actual argument to another
procedure. This can be useful because it allows a program to
spawn different versions of the function that can have access to
different instances of the host (for a recursive host).

For other purposes I generally think internal procedures aren't
all that useful, except perhaps as a substitute for statement
functions. After all, if the function were that useful, wouldn't
it make sense to make it another module procedure so all program
units could have direct access to it?

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


glen herrmannsfeldt

unread,
Oct 2, 2012, 6:19:27 PM10/2/12
to
James Van Buskirk <not_...@comcast.net> wrote:

(snip on internal functions)

> The function can be invoked from program units other than the host
> or its sibling internal procedures in f2008, by pointing a Fortran
> procedure pointer at it or taking its C_FUNLOC and passing one of
> those or the function itself as an actual argument to another
> procedure. This can be useful because it allows a program to
> spawn different versions of the function that can have access to
> different instances of the host (for a recursive host).

> For other purposes I generally think internal procedures aren't
> all that useful, except perhaps as a substitute for statement
> functions. After all, if the function were that useful, wouldn't
> it make sense to make it another module procedure so all program
> units could have direct access to it?

Personally, I still like statement functions for very simple
operations that you might need to do in many places. An old
favorite is degree/radian conversion. I hope most compilers
now expand them inline, but maybe not all.

For things that are slightly more complicated, but still
specific to the one procedure, they are nice. Also, for small
programs that don't need any external or module functions.

-- glen

Robin Vowels

unread,
Oct 2, 2012, 8:11:18 PM10/2/12
to
On Oct 3, 6:18 am, Gordon Sande <Gordon.Sa...@gmail.com> wrote:

> Before the era of commodity 32 bits chips there were major vendors
> offering 36 bit, 48 bit
> and 60 bit machines. Byte has not always been very well defined and
> could mean 6, 7 or 8
> bits. There have even been major vendors who offered machines with
> differing floating point
> formats within the same word size.

There still are.

Ron Shepard

unread,
Oct 3, 2012, 2:36:28 AM10/3/12
to
In article <k4femh$9b0$1...@dont-email.me>,
Simon Geard <jo...@whiteowl.co.uk> wrote:

> My experience of the hundreds of thousands of lines of Fortran I've
> worked on professionally since 1985 on the above machines is that no one
> has ever used the 'widely recommended way'. Not once.

That does sound odd. I have been using f90 and later since about
1993, and I don't think I have ever hardwired a kind number in a
code. I always use a parameter, and that parameter is almost always
defined using selected_real_kind(). In special cases I might use
kind(1d0) or kind(1.0), but for my application codes that is the
exception.

$.02 -Ron Shepard

Wolfgang Kilian

unread,
Oct 4, 2012, 2:48:30 AM10/4/12
to
On 10/02/2012 10:39 PM, James Van Buskirk wrote:
> "Arjen Markus"<arjen.m...@gmail.com> wrote in message
> news:6adbe8dc-e0ab-4510...@googlegroups.com...
>
>> Such an internal function works in much the same way as functions in
>> a module. The exception is that it can not be used outside the context of
>> the containing program unit.
>
> The function can be invoked from program units other than the host
> or its sibling internal procedures in f2008, by pointing a Fortran
> procedure pointer at it or taking its C_FUNLOC and passing one of
> those or the function itself as an actual argument to another
> procedure. This can be useful because it allows a program to
> spawn different versions of the function that can have access to
> different instances of the host (for a recursive host).

... which can also be done by binding functions to a derived type which
holds the host data. It depends whether the algorithm is more naturally
expressed in terms of procedures or in terms of objects (data), so it is
good that Fortran (2008) supports both.

> For other purposes I generally think internal procedures aren't
> all that useful, except perhaps as a substitute for statement
> functions. After all, if the function were that useful, wouldn't
> it make sense to make it another module procedure so all program
> units could have direct access to it?

Internal procedures come handy for recursive algorithms: the host is an
ordinary procedure which hides the recursive internal procedure. The
internal procedure takes as arguments only those parameters which depend
on the recursion level.

-- Wolfgang

--
E-mail: firstnameini...@domain.de
Domain: yahoo

Georg Waldgreve

unread,
Oct 4, 2012, 4:18:05 AM10/4/12
to
Am 04.10.2012 08:48, schrieb Wolfgang Kilian:
- - - snip - - -
>
> Internal procedures come handy for recursive algorithms: the host is an
> ordinary procedure which hides the recursive internal procedure. The
> internal procedure takes as arguments only those parameters which depend
> on the recursion level.
>
> -- Wolfgang
>
I understand your remarks about CONTAINS, but could you please tell me
what would be the advantage to hide the recursive internal procedure in
an ordinary procedure as a host?

Georg Waldgreve

Wolfgang Kilian

unread,
Oct 4, 2012, 5:28:51 AM10/4/12
to
Two advantages:

1) The internal subroutine can access host variables as 'globals'. For
instance, objects that do not depend on recursion level. This
simplifies the interface of the recursive subroutine. Nevertheless,
these 'globals' are local to the outer procedure which is externally
visible, so there is no actual global state involved. (Considering
global state variables as a problem, e.g., for parallelization)

2) The implementation (the recursive internal procedure) is hidden, only
the interface (the arguments of the outer procedure) is exposed.
Changing the implementation later is easy, e.g., replacing the recursion
by an iterative algorithm.

James Van Buskirk

unread,
Oct 4, 2012, 10:29:04 AM10/4/12
to
"Wolfgang Kilian" <see...@domain.invalid> wrote in message
news:k4jbfv$jkc$1...@dont-email.me...

> On 10/02/2012 10:39 PM, James Van Buskirk wrote:

>> The function can be invoked from program units other than the host
>> or its sibling internal procedures in f2008, by pointing a Fortran
>> procedure pointer at it or taking its C_FUNLOC and passing one of
>> those or the function itself as an actual argument to another
>> procedure. This can be useful because it allows a program to
>> spawn different versions of the function that can have access to
>> different instances of the host (for a recursive host).

> ... which can also be done by binding functions to a derived type which
> holds the host data. It depends whether the algorithm is more naturally
> expressed in terms of procedures or in terms of objects (data), so it is
> good that Fortran (2008) supports both.

I wouldn't say that the method with type-bound procedures spawns
new versions of the function. The function as written must have a
dummy argument that is the instance of the derived type that
contains the data. Then the procedure that invokes it must do so
as T%method() so that the Fortran processor knows which instance of
the derived type to provide as the passed object dummy argument. As
a consequence the procedure that ultimately does the invoking of
T%method() must be written not only in Fortran, but the same
compiler as the one that did the binding of the function method()
to type T.

The technique with internal procedures to recursive procedures
actually creates new addresses (entry points) at run time. Try
checking with TRANSFER(C_FUNLOC(method),0_C_INTPTR_T). In this
case the different versions can be invoked by completely
different languages as long as their interface is effectively
f77 or BIND(C).

glen herrmannsfeldt

unread,
Oct 4, 2012, 12:02:11 PM10/4/12
to
Wolfgang Kilian <see...@domain.invalid> wrote:
> On 10/04/2012 10:18 AM, Georg Waldgreve wrote:
>> Am 04.10.2012 08:48, schrieb Wolfgang Kilian:
>> - - - snip - - -

>>> Internal procedures come handy for recursive algorithms: the host is an
>>> ordinary procedure which hides the recursive internal procedure. The
>>> internal procedure takes as arguments only those parameters which depend
>>> on the recursion level.

>> I understand your remarks about CONTAINS, but could you please tell me
>> what would be the advantage to hide the recursive internal procedure in
>> an ordinary procedure as a host?

Many recursive problems are best written using loops.

The ever favorite for introduction to recursion is the factorial
function, which is easy to write as a loop. As the values grow
exponentially, the maximum stack depth isn't so high.

Another popular one for introduction to recursion is Fibonacci,
which is horrible. The execution time increases exponentially
for what should be a linear algorithm.

> Two advantages:

> 1) The internal subroutine can access host variables as 'globals'. For
> instance, objects that do not depend on recursion level. This
> simplifies the interface of the recursive subroutine. Nevertheless,
> these 'globals' are local to the outer procedure which is externally
> visible, so there is no actual global state involved. (Considering
> global state variables as a problem, e.g., for parallelization)

Simple operations on trees are easiest to describe recursively.
Even without getting information in from the host, it is often
nice to have them internal.

> 2) The implementation (the recursive internal procedure) is hidden, only
> the interface (the arguments of the outer procedure) is exposed.
> Changing the implementation later is easy, e.g., replacing the recursion
> by an iterative algorithm.

Yes, as above this works well for operations on trees. Sometimes
the outer routine can directly call itself, but often the first
call has to do a little extra work before calling the recursive
routine.

And yes, sometimes it is useful to go back later and use
iteration instead of recursion.

-- glen

Ron Shepard

unread,
Oct 4, 2012, 1:02:16 PM10/4/12
to

> For other purposes I generally think internal procedures aren't
> all that useful, except perhaps as a substitute for statement
> functions.

Here is one counterexample. I have a routine that involves four
nested loops

do i = 1, n
do j = i+1, n
do k = j+1, n
do l = k+1, n
enddo
enddo
enddo
enddo

Each of the loop code has this kind of structure.

...do some stuff to setup the next loop...
...do the next loop...
...do some cleanup stuff for this loop...

I wanted to have the first and last steps next to each other in the
code because they are related. But if I just wrote the code in a
straightforward way, then those sections of code would be not only
not next to each other, they would have been several screens of code
separated.

So, I used internal procedures to replace all of the individual
inner loops that looked like this.

subroutine jloop
do j = i+1, n
...do some stuff to setup the next loop...
call kloop
...do some cleanup stuff for this loop...
enddo
end subroutine jloop

with the same structure for subroutines kloop and lloop (except
lloop doesn't call anything else). This keeps the setup and cleanup
sections of code together, so everything is clear.

All of the local variables in the main subroutine are shared, and I
ended up not even declaring any local variables within the contained
subroutines.

At some time in the future I may extend this to six or eight levels
of nested loops, so when I do that, the advantages of the internal
procedure approach will be even larger.

$.02 -Ron Shepard

James Van Buskirk

unread,
Oct 4, 2012, 8:26:58 PM10/4/12
to
"Ron Shepard" <ron-s...@NOSPAM.comcast.net> wrote in message
news:ron-shepard-5CD6...@news60.forteinc.com...
There is a cost for using host state. In f2008, or dvf/cvf/ifort
since forever, procedures outside the host could invoke the internal
subroutines. Before calling the internal subroutine itself, the
caller would have to invoke a front-end subroutine that loads a
pointer to the host data and then invokes the internal subroutine.
You could do this yourself by packing all the data into a user-
defined type and passing the UDT through the chain of subroutines.

If there is a loop whose nesting depth you don't know at compile
time, or if you want to be able to easily change the nesting
depth, it seems to be a good candidate for a single recursive
subroutine rather than a chain of subroutines as you have
outlined above.

glen herrmannsfeldt

unread,
Oct 4, 2012, 10:30:09 PM10/4/12
to
James Van Buskirk <not_...@comcast.net> wrote:

(snip, someone wrote)
>> So, I used internal procedures to replace all of the individual
>> inner loops that looked like this.

(snip)

>> At some time in the future I may extend this to six or eight levels
>> of nested loops, so when I do that, the advantages of the internal
>> procedure approach will be even larger.

> There is a cost for using host state. In f2008, or dvf/cvf/ifort
> since forever, procedures outside the host could invoke the internal
> subroutines. Before calling the internal subroutine itself, the
> caller would have to invoke a front-end subroutine that loads a
> pointer to the host data and then invokes the internal subroutine.
> You could do this yourself by packing all the data into a user-
> defined type and passing the UDT through the chain of subroutines.

PL/I has ENTRY variables (its name for procedure pointers)
which, I believe in the usual implementation, include the
appropriate pointer. But plenty of parts of PL/I have a cost
that one might rather not have.

> If there is a loop whose nesting depth you don't know at compile
> time, or if you want to be able to easily change the nesting
> depth, it seems to be a good candidate for a single recursive
> subroutine rather than a chain of subroutines as you have
> outlined above.

Oh, this reminds me so much of an FFT routine I saw in the F66 days.

Well, recursion, or its implmentation by saving data on some
explicit stack, has a cost that might be higher than one likes.

For the FFT routine, what you want is N nested DO loops, each
from 1 to 2. In the routine I remember, they had many nested
loops, then GOTO into the appropriate one, and GOTO out just
after the end of that loop, depending on the value of N
(an argument to the routine).

About as non-standard as can be (no connection to extended range
of the DO), but it seems to have worked on at least one compiler.

I might have thought that the cost of the GOTO and IF wasn't
so low, but apparently it worked at the time.

Otherwise, I would just make many different blocks with different
nesting levels and use the right one. But memory is cheap now,
and wasn't in the F66 days.

-- glen

Wolfgang Kilian

unread,
Oct 5, 2012, 3:12:52 AM10/5/12
to
But if it is only 'effectively' cross-language (no BIND(C)), there is no
guarantee, right? I can imagine a compiler agressively optimizing
internal procedures away, provided they are not adressed by Fortran
standard means as procedure pointer targets or actual arguments.

In functional languages where recursion is a common programming style,
recursive functions are often optimized by the compiler, automatically
converting them to loops.

Ian Harvey

unread,
Oct 5, 2012, 7:19:40 AM10/5/12
to
Without BIND(C) I also suspect it is possible to implement procedure
pointers to internal procedures in the same way as a for the type bound
procedure example - the procedure pointer stores a pointer to the host
context (~the derived type data) and the procedure entry point (~ the
binding). Call the entry point without setting up the context and life
could get exciting.
0 new messages