From: Den7 on
Please look at this code, why this code is forbidden (in my compiler
at least) ?

integer foo
external foo

open(11,file='11.out')
open(12,file='12.out')
write(11,*) foo(12)
end

integer function foo(i)
write(12,*) i
1000 foo=i
end function foo

Even if i write into character variable (so called internal write or
something like that) i have the same problem.
Even more, if i make

write(12,*,err=1000) i

i still have the crash. How about your compiler?

The error is "The function called from within an I/O statement has
itself performed an I/O".
It sounds to me as silly as this: "The function called from within
multiplication has itself performed a multiplication", but there could
be nasty reasons for forbidding this kind of I/Os requiring
multithreading or so.

How old VAX ENCODE is implemented in your compiler? Is it done via
internal write or by some proprietary other non-I/O way? In other
words, can you check if this code below is also crashing, and if it
does, is it crashing on ENCODE line statement or on the next lines
with WRITE statement? Or may be your compiler allows all these writes
and you do not experience a problem at all despite the standard may
forbid that? (Please also check syntax of this snippet, i can not run
it, my compiler does not support these long forbidden ENCODE/DECODE
extensions)

open(11,file='11.out')
open(12,file='12.out')
write(11,*) foo(1)
end

integer function foo(i)
character*9 CHAR_I

ENCODE (9,1,CHAR_I) i
1 format (i9)
write(12,*) char_i

write(12,*) i

foo=i
end

TIA !
From: glen herrmannsfeldt on
Den7 <rrr7rrr(a)gmail.com> wrote:
> Please look at this code, why this code is forbidden (in my compiler
> at least) ?

> integer foo
> external foo
> open(11,file='11.out')
> open(12,file='12.out')
> write(11,*) foo(12)
> end

> integer function foo(i)
> write(12,*) i
> 1000 foo=i
> end function foo

> Even if i write into character variable (so called internal write or
> something like that) i have the same problem.
> Even more, if i make

> write(12,*,err=1000) i

> i still have the crash. How about your compiler?

The usual implementation has a subroutine call to start,
specifying the unit, format, and other options, then one call per
element in the I/O list, and finally one to finish the I/O operation.

If you do I/O in a function then things get mixed up. This restriction
came when machines had much smaller main memory than they do today.

For the internal I/O case, I believe the restriction was removed
in Fortran 2003.

> The error is "The function called from within an I/O statement has
> itself performed an I/O".

Yes, see above.

> It sounds to me as silly as this: "The function called from within
> multiplication has itself performed a multiplication", but there could
> be nasty reasons for forbidding this kind of I/Os requiring
> multithreading or so.

It happens even without multithreading. Systems can, for example,
reuse buffers. You can see, though, that I/O to the same unit could
still be a problem.

As to multiplication, you can't call a function in the middle of
a multiply operation. There are restictions on changing variables
used in the same expression, though. Consider:

integer foo
i=3
j=i*foo(i)
print *,i,j
end
integer function foo(k)
foo=k
k=k+1
return
end

> How old VAX ENCODE is implemented in your compiler? Is it done via
> internal write or by some proprietary other non-I/O way? In other
> words, can you check if this code below is also crashing, and if it
> does, is it crashing on ENCODE line statement or on the next lines
> with WRITE statement? Or may be your compiler allows all these writes
> and you do not experience a problem at all despite the standard may
> forbid that? (Please also check syntax of this snippet, i can not run
> it, my compiler does not support these long forbidden ENCODE/DECODE
> extensions)

ENCODE/DECODE were in DEC Fortran 66 compilers. Internal I/O
wasn't added to Fortran until Fortran 77. Presumably slowly removed
as internal I/O became more popular.

-- glen
From: Richard Maine on
Den7 <rrr7rrr(a)gmail.com> wrote:

> Please look at this code, why this code is forbidden
....
> The error is "The function called from within an I/O statement has
> itself performed an I/O".
> It sounds to me as silly as this:...

Well, the simple answer is that it is forbidden because the standard
says so. Guessing based on what "sounds silly" doesn't tend to be very
reliable, at least until one becomes quite an expert; even then one's
guesses sometimes come out wrong. (Trust me on that part. :-))

If you want a slightly deeper "why", this one isn't actually
particularly difficult. This kind of thing is called recursive I/O.
There have been compiler implementations where the I/O routines were not
reentrant in the ways required to make this work.

Note that the Fortran standard is about what you can count on working in
*ALL* implementations. The fact that it might work with some compiler
implementations isn't good enough.

Also note that the restriction in question originated several decades
ago. There existed major compiler implementations of the time where
reentrancy was a major pain. Even if one might argue (as people have)
that such compilers could have been done otherwise, that wasn't the
question at hand. Arguing about what should have been different in the
past tends to be pointless (unless one first spends a lot of time in
understanding the context of the era).

Current compiler technology is a different matter. As of f2003, this
code is standard. Odds are reasonably good that many recent f90/f95
compilers allow it, as did some f77 ones. But you can't count on it
until f2003. It is the kind of thing that I would suggest not counting
on unless it is specifically documented as being supported, insomuch as
bugs relating to reentrancy can easily hide in simple testing, only to
surface later in more complicated situations.

Some cases of recursive I/O also have other complications. That's
particularly so of cases where the recursive I/O is to the same file.
But that's not a problem when the I/O in the function is to an internal
file.

> How old VAX ENCODE is implemented in your compiler? Is it done via
> internal write or by some proprietary other non-I/O way?

That question doesn't really make much sense. Encode is a bit of
language syntax, as is internal I/O. You don't implement one piece of
language syntax via another (well, not normally; when you do, that's
generally called a preprocessor). And encode preceded internal write, so
it scarely would have been implemented that way.

I'm not going to bother to try to check the sample encode snippet. I
don't recall whether encode is supported at all on the compilers I have
handy, and even if it was, such a test would show nothing useful. Of
course,the standard "forbids" it, as encode has always been nonstandard.
I don't need to run compilers test sto tell that; reading the standard
tells me much better. That doesn't mean it might or might not work in
any particular compiler. And it working with one compiler would tell
nothing about whether it would work with another. Nor would it tell
anything about recursive internal I/O.

Anyway...

Prior to f2003, I recommend one of two solutions for recursive I/O.

1. Make it non-recursive by invoking the function in a separate
statement before the I/O and storing the result in a variable. In some
cases, one might as well then also make it a subroutine.

or

2. Avoid I/O in the function, even internal I/O. One can sometimes do
the equivalent functionality (such as converting between
integer/character) by writing it out in detail. Yes, that can be
awkward. That's why internal I/O came about to take advantage of the
compiler runtimes already having implemented that for you. That's also
why f2003 allows recursive internal I/O - because it is often
convenient. But I've done the "longhand" version in simple cases where
it only adds a few lines.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
From: Richard Maine on
glen herrmannsfeldt <gah(a)ugcs.caltech.edu> wrote:

> As to multiplication, you can't call a function in the middle of
> a multiply operation.

Well, yes you can if the multiply operation is implemented via a defined
operation (which you can't do for the cases where the standard defines
an intrinsic multiply.)

If you happen to do a defined operation for multiply, you will run into
the same kinds of limitations. In particular, your multiply routine may
not recursively invoke itself (unless it is explicitly declared to be
recursive). This is indeed something that could relistically come up if
one was doing defined operations.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
From: Tim Prince on
Den7 wrote:
........
Fortran 2003 permits recursive I/O in a limited set of circumstances,
specifically excluding operating on multiple external units, as you
suggest you would like to do. F2003 does support use of internal file
I/O in a recursive situation, such as might have been done with VAX
ENCODE over 30 years ago.
Under standards before f2003, there was no requirement to support
recursive I/O, and there are several compilers still existent which
don't go beyond f95 I/O.