Print

Print


On Nov 30, 2004, at 1:40 AM, Bertrand Meltz wrote:

> I often use this piece of program in my codes.
> Some compilers insist that this is a recursive library call.
> Is it really?
   [code elided]

Yes. This is *EXACTLY* the kind of thing that the recursive I/O
restriction is about. Speaking sloppily (if you wanted the formal
version, I could quote the standard's words, but perhaps my sloppy
words will provide a different perspective - or maybe not)...

You are in the process of doing I/O (namely the print *) when the
function is called.  That function then does I/O itself.

> It does not seem to me to be "more recursive" than
> a = MAX( b, MAX( c, d))
> which always works.

which is besides the point. The standard doesn't restrict that; it does
explicitly restrict recursive I/O. One could go on for a long time with
reasons. I'll just briefly mention a few.

1. Getting a bit historical, but many compilers used to have I/O
libraries that couldn't handle this without a complete rewrite (so I am
told). I/O libraries are big and complicated and thus a big deal to
rewrite.  Max isn't. My understanding is that by now, most I/O
libraries have already bitten this particular bullet, but that didn't
used to be true.

2. There are cases where it is hard to even define what recursive I/O
would mean. That's particularly so when the recursive I/O is to the
same unit. This particular case doesn't have that problem, but realize
that there are many, many restrictions in the standard that are broader
than absolutely necessary because it would add complication (sometimes
very large amounts) to precisely delimit the problem cases. In the case
of recursive I/O, it has been decided that a few cases (including this
one) are safe, common, and useful enough, and easy enough to describe,
so that the boundary of the prohibition was moved in f2003. There is
still a prohibition, but its boundary moved past this case. In
particular, internal I/O is allowed.

3. The situation with max has a fundamental difference that you
probably don't appreciate because your I/O statement is so simple. I/O
can get really complicated. The standard has to cover all the cases.
And as mentioned in point 2, it is sometimes messy to draw a precise
boundary betweeen safe cases and problem ones.

In particular, the arguments to a procedure are in principle (and
usually in fact) evaluated *BEFORE* calling the procedure. Thus your
example with max isn't really recursive; there aren't 2 "copies" of MAX
running at the same time. The "innermost" MAX invocation is completed
(at least in principle - optimizers can play tricks) before the
outermost one is called.

But I/O statements can't always work that way.  Yours is simple enough
that it can. But in more complicated cases, you have to actually do
some of the I/O for early items in the list before you can evaluate
later items. Thus I/O cannot be described in all cases by saying to
first evaluate the I/O list and then do the I/O. You have to first
start the I/O and then work through the I/O list. This means that there
are 2 "copies" of the I/O runtimes active at the same time if there is
any I/O in functions in the original I/O list.

A a final reminder, mentioned above, but worth highlighting. This code
is ok in f2003, just not in f95 or earlier. (Though I'm sure some f95
compilers allow it as an extension... perhaps not even intentionally,
but just that it works).

--
Richard Maine                |  Good judgment comes from experience;
[log in to unmask]       |  experience comes from bad judgment.
                             |        -- Mark Twain