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

Question(s) about recursive I/O in f2003

17 views
Skip to first unread message

dom...@lps.ens.fr

unread,
Feb 7, 2007, 4:09:38 PM2/7/07
to
Could someone give a pointer to a tutorial about recursive I/O in
F2003?
I would like to understand what they are supposed to do and what are
the restrictions set by the standard.

Thanks in advance

Dominique

Lane Straatman

unread,
Feb 7, 2007, 4:51:49 PM2/7/07
to

<dom...@lps.ens.fr> wrote in message
news:1170882578.4...@s48g2000cws.googlegroups.com...
The first function I wrote in fortran was recursive and elementary. The
forum helped me with a critical step in the logic. At the end of the
function, the IO was just a big fat write *,* statement.

Recursive io is not something I've heard of. LS


Michael Metcalf

unread,
Feb 7, 2007, 5:02:45 PM2/7/07
to

"Lane Straatman" <inv...@invalid.net> wrote in message
news:dICdnfbodsHh1FfY...@comcast.com...
That's perhaps because it's not permitted to have a function reference in an
I/O statement that causes further I/O to occur (MR&C, Section 9.3). OP is
perhaps thinking of non-default derived-type I/O in Fortran 2003. This is
achieved by user-written subroutines that may be recursive (Sections 19.3
and 19.7).

HTH

Mike Metcalf


James Giles

unread,
Feb 7, 2007, 5:26:35 PM2/7/07
to
dom...@lps.ens.fr wrote:
> Could someone give a pointer to a tutorial about recursive I/O in
> F2003?
> I would like to understand what they are supposed to do and what are
> the restrictions set by the standard.

Well, first of all the term is a misnomer. There is no actual
recursion involved. Consider the following write statement:

Write(io_unit(p)) f(x)

And suppose IO_UNIT is a function. Suppose further that
there's I/O done within that function. Well, you might think
that the normal way to do this is to call the IO_UNIT function
before you call the I/O library to process the WRITE. And,
you could do that too, but many implementations don't (I'll
talk about what they actually do below).

And suppose that F is a function that also does I/O. Again,
you might think the proper thing to do is call F first and then
call the I/O library to process the WRITE. Again, implementations
could do that, but most don't.

What most implementations do when they process an I/O
statement is begin a sequence of calls to the I/O library.
The first initializes the process: prepares the library for the
type of I/O you're about to do (in this case, unformatted
write). The last step is to finalize the I/O process (which
might actually send any data buffered within the library
itself to the system - no, it's not what FLUSH does - and
maybe even return such internal buffers to the memory
manager). In between, there are several calls to the I/O
library that pass information to be processed next. There
might be a separate call for the unit number, for the format
(in this case, there isn't one, but for formatted I/O there
would be), and a separate call for each I/O list item. Etc.

So, each I/O statement actually turns into a whole sequence
of procedure calls. And the function references we discussed
above might be made in between some of these I/O calls.
Since F(X), for example, also does I/O, the library is brought
into a distinct sequence of activity from the one it's already
doing. And that's what's called "recursive I/O". Since most
libraries aren't prepared for that kind of interruption, the
programmer is forbidden to do it. The one kind of such I/O
that's now permitted is that an I/O control list item or an
I/O list item may now do internal I/O (that is, read from
or write to a character string), but not additional external
I/O.

Now, why would an implementation do things like that?
Well consider:

Write(11) (F(i), i = 1, max), (G(j), j = 1, max), ...

Where MAX is some large number. In order to precompute
the whole I/O list before beginning the I/O sequence you have
to make room for huge numbers of temporary values. It's
easier nowdays. But when the usual I/O imlementation
style was invented memory was not so cheap or abundant.
Even so, suppose that F is an array valued function: it could
still add up to a prohibitive amount of memory. By processing
the I/O list incrementally you avoid the need for large amounts
of such temporary storage.

Note: few I/O implementations don't precompute the I/O control
list items (the stuff in the parenthesis after the statement keyword).
So, "recursive I/O" is probably safe there. But, I see no mention
of it either way in the standard document. Maybe I'm looking in the
wrong places.

--
J. Giles

"I conclude that there are two ways of constructing a software
design: One way is to make it so simple that there are obviously
no deficiencies and the other way is to make it so complicated
that there are no obvious deficiencies." -- C. A. R. Hoare


Richard Maine

unread,
Feb 7, 2007, 5:49:53 PM2/7/07
to
Michael Metcalf <michael...@compuserve.com> wrote:

> "Lane Straatman" <inv...@invalid.net> wrote in message
> news:dICdnfbodsHh1FfY...@comcast.com...
> >
> > <dom...@lps.ens.fr> wrote in message
> > news:1170882578.4...@s48g2000cws.googlegroups.com...
> >> Could someone give a pointer to a tutorial about recursive I/O in
> >> F2003?
> >> I would like to understand what they are supposed to do and what are
> >> the restrictions set by the standard.

> > Recursive io is not something I've heard of. LS
> That's perhaps because it's not permitted to have a function reference in an
> I/O statement that causes further I/O to occur (MR&C, Section 9.3). OP is
> perhaps thinking of non-default derived-type I/O in Fortran 2003. This is
> achieved by user-written subroutines that may be recursive (Sections 19.3
> and 19.7).

UDDTIO (a horrible term, so long that even nobody in J3 ever actually
spells out User-Defined Derived-Type Input/Output in conversation) is
the somewhat esoteric case. The other case allowed in f2003 is much
simpler and likely to be used far more often; in fact, it is one that
has come up here with fair regularity, adn one that some (many?)
existing compilers support.

Namely, so-called recursive I/O is allowed to/from an internal file.
That is, you can do internal I/O in a function invoked from an I/O
statement. This is an often-requested feature.

All the other cases are still disallowed.

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

glen herrmannsfeldt

unread,
Feb 8, 2007, 3:55:16 AM2/8/07
to
James Giles wrote:

(snip)

> Well, first of all the term is a misnomer. There is no actual
> recursion involved. Consider the following write statement:

> Write(io_unit(p)) f(x)

Well, reentrant is closely related to recursive. It is
reentrant in the sense that the routine is entered again
before the previous I/O statement has completed.

> And suppose IO_UNIT is a function. Suppose further that
> there's I/O done within that function. Well, you might think
> that the normal way to do this is to call the IO_UNIT function
> before you call the I/O library to process the WRITE. And,
> you could do that too, but many implementations don't (I'll
> talk about what they actually do below).

I believe it is fairly common for the unit to be specified
in the initial call, and reasonably likely the format, too.
As far as I know, the standard doesn't require it.

> And suppose that F is a function that also does I/O. Again,
> you might think the proper thing to do is call F first and then
> call the I/O library to process the WRITE. Again, implementations
> could do that, but most don't.

> What most implementations do when they process an I/O
> statement is begin a sequence of calls to the I/O library.
> The first initializes the process: prepares the library for the
> type of I/O you're about to do (in this case, unformatted
> write). The last step is to finalize the I/O process (which
> might actually send any data buffered within the library
> itself to the system - no, it's not what FLUSH does - and
> maybe even return such internal buffers to the memory
> manager). In between, there are several calls to the I/O
> library that pass information to be processed next. There
> might be a separate call for the unit number, for the format
> (in this case, there isn't one, but for formatted I/O there
> would be), and a separate call for each I/O list item. Etc.

As far as I know, it is the list items that are usually
the problem.

> So, each I/O statement actually turns into a whole sequence
> of procedure calls. And the function references we discussed
> above might be made in between some of these I/O calls.

(snip)

> Now, why would an implementation do things like that?
> Well consider:

> Write(11) (F(i), i = 1, max), (G(j), j = 1, max), ...

> Where MAX is some large number. In order to precompute
> the whole I/O list before beginning the I/O sequence you have
> to make room for huge numbers of temporary values. It's
> easier nowdays. But when the usual I/O imlementation
> style was invented memory was not so cheap or abundant.
> Even so, suppose that F is an array valued function: it could
> still add up to a prohibitive amount of memory. By processing
> the I/O list incrementally you avoid the need for large amounts
> of such temporary storage.

I do remember when the OS/360 Fortran library was changed to
allow an array or implied do as one call, instead of one per
array element. The new library was backward compatible, but
new code was not compatible with the old library.

> Note: few I/O implementations don't precompute the I/O control
> list items (the stuff in the parenthesis after the statement keyword).
> So, "recursive I/O" is probably safe there. But, I see no mention
> of it either way in the standard document. Maybe I'm looking in the
> wrong places.

As far as I know, not, but I don't know where it says it, either.

-- glen

robert....@sun.com

unread,
Feb 8, 2007, 5:36:31 AM2/8/07
to
On Feb 7, 2:26 pm, "James Giles" <jamesgi...@worldnet.att.net> wrote:

> Note: few I/O implementations don't precompute the I/O control
> list items (the stuff in the parenthesis after the statement keyword).
> So, "recursive I/O" is probably safe there. But, I see no mention
> of it either way in the standard document. Maybe I'm looking in the
> wrong places.

The Fortran 2003 standard is clear in this case. Section 9.11
states

An input/output statement that is executed while another
input/output statement is being executed is called a
recursive input/output statement.

A recursive input/output statement shall not identify an
external unit except that a child data transfer statement
may identify it parent data transfer statement external
unit.

For example, if the statement

READ (UNIT=IF())

starts executing by calling the function IF and during the
execution of IF any new input/output statement that
identifies an external unit is executed, the program is
not standard-conforming and the behavior of the
program is not defined by the standard.

Even if this restriction on recursive input/output is
unnecessary or undesireable, it is, nonetheless, a part
of the Fortran 2003 standard.

Bob Corbett

robert....@sun.com

unread,
Feb 8, 2007, 6:07:45 AM2/8/07
to
On Feb 7, 2:26 pm, "James Giles" <jamesgi...@worldnet.att.net> wrote:

> Note: few I/O implementations don't precompute the I/O control
> list items (the stuff in the parenthesis after the statement keyword).
> So, "recursive I/O" is probably safe there. But, I see no mention
> of it either way in the standard document. Maybe I'm looking in the
> wrong places.

The Fortran 2003 standard is clear in this case. Section 9.11

James Giles

unread,
Feb 8, 2007, 5:17:09 PM2/8/07
to
glen herrmannsfeldt wrote:
> James Giles wrote:
>
> (snip)
>
>> Well, first of all the term is a misnomer. There is no actual
>> recursion involved. Consider the following write statement:
>
>> Write(io_unit(p)) f(x)
>
> Well, reentrant is closely related to recursive. It is
> reentrant in the sense that the routine is entered again
> before the previous I/O statement has completed.

Actually not. The I/O library does not call the functions
IO_UNIT and F. Those calls are often made *between*
the calls to the I/O library. It is the *sequence* of calls
that has to be re-entrant. The individual procedures need
not be unless your library needs to handle multiple threads.

...


> I believe it is fairly common for the unit to be specified
> in the initial call, and reasonably likely the format, too.
> As far as I know, the standard doesn't require it.

As I said.

glen herrmannsfeldt

unread,
Feb 8, 2007, 5:34:12 PM2/8/07
to
James Giles wrote:

(snip)

>>Well, reentrant is closely related to recursive. It is


>>reentrant in the sense that the routine is entered again
>>before the previous I/O statement has completed.

> Actually not. The I/O library does not call the functions
> IO_UNIT and F. Those calls are often made *between*
> the calls to the I/O library. It is the *sequence* of calls
> that has to be re-entrant. The individual procedures need
> not be unless your library needs to handle multiple threads.

That is what I meant, if not what I said. As an I/O statement
comprises multiple I/O library calls, execution of another
I/O statement enters the library routine before it has
finished the previous I/O statement. Also, the individual
procedures are usually multiple entry points into the same
procedure, with many data structures in common.

In the usual definition of recursive, a routine calls itself,
either directly or indirectly. That usually requires it
to be reentrant. Reentrant routines are also needed for
multithreading, where they may be called by different threads,
though neither is recursive. (Another thing to watch out
for: Fortran I/O in multithreaded programs.)

thanks,

-- glen

James Giles

unread,
Feb 8, 2007, 6:08:30 PM2/8/07
to
glen herrmannsfeldt wrote:
> [...] Reentrant routines are also needed for

> multithreading, where they may be called by different threads,
> though neither is recursive. (Another thing to watch out
> for: Fortran I/O in multithreaded programs.)

When I wrote an I/O support library for Fortran (f77 in
those days), the rule was that the programmer could have
as many I/O operations going at once as desired provided
that each operation involved a distinct file. So, you could
have "recursive I/O" or multiple threads doing I/O, but
each I/O operation had to be working on a different external
file or a different internal file. (Well, actually multiple
threads could simultaneously READ the same external file
through different unit numbers. But that's pretty far from
the discussion of "recursive I/O".) Yes, do all that the
library routines really did have to be reentrant.

Brooks Moses

unread,
Feb 9, 2007, 5:00:00 AM2/9/07
to
robert....@sun.com wrote:
> On Feb 7, 2:26 pm, "James Giles" <jamesgi...@worldnet.att.net> wrote:
>
>> Note: few I/O implementations don't precompute the I/O control
>> list items (the stuff in the parenthesis after the statement keyword).
>> So, "recursive I/O" is probably safe there. But, I see no mention
>> of it either way in the standard document. Maybe I'm looking in the
>> wrong places.
>
> The Fortran 2003 standard is clear in this case. Section 9.11
> states
>
> An input/output statement that is executed while another
> input/output statement is being executed is called a
> recursive input/output statement.
>
> A recursive input/output statement shall not identify an
> external unit except that a child data transfer statement
> may identify it parent data transfer statement external
> unit.

That's not clear until you know what "child data transfer statement"
means, though. :) It took me a while to find that it's defined as part
of the UDDTIO things, rather than just being a way of describing whether
one is referring to the first or section I/O statement mentioned in the
first paragraph you quote....

- Brooks

--
The "bmoses-nospam" address is valid; no unmunging needed.

0 new messages