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 !
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
> 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
> 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.
> glen herrmannsfeldt <g...@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.
Oh. It occurred to me right after posting the above that it might be
worth pointing out another relationship between these matters. The f2003
feature of allowing recursive internal I/O was directly related to
defined I/O (which in turn is related to defined operations).
In particular, when defined I/O was added to f2003 (which was a subject
of controversy, but that's a side issue for the current topic), one
particular case of recursive I/O pretty much had to be allowed. Namely,
you really have to be able to do I/O in a defined I/O routine or the
whole thing becomes pointless. Once the camel's nose was in that
particular door, the argument was made that this required the underlying
functionality be supported, so might as well also allow the case that
"everyone" asks for - namely internal I/O like in the OP's post.
> he case that
> "everyone" asks for - namely internal I/O like in the OP's post.
Oops. I didn't go back and check the OP's post before writing that. His
case isn't internal I/O after all.
Most likely in Fortran II when functions written in Fortran were
added to the language. Reasonably likely only one buffer was used
for all I/O operations, and statically allocated.
(snip)
>> 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.
Well, ENCODE was in the PDP-10 and PDP-11 Fortran IV (Fortran 66 more
or less) compilers. The first VAX compilers were Fortran 66, with
the Fortran 77 compilers coming along a little later. It might be
that the first ones ran in PDP-11 compatability mode.
DEC had many extensions that IBM didn't have, ENCODE being one of them.
(snip)
-- glen
Sun Fortran has allowed "recursive" I/O involving
different I/O units since the 2.0 release of Sun f90.
It was hard to implement, but it was well worth the
effort.
Allowing recursive I/O to the same unit is an often
requested extension, but it is problematic. What
should happen if a program closes a file in the middle
of writing to that file? One case that could be allowed
and that seems to be what most people who ask for the
extension want is to allow a formatted WRITE on a unit
which is already being used in another formatted WRITE.
Bob Corbett
> (snip)
>
>>> 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.
>
> Well, ENCODE was in the PDP-10 and PDP-11 Fortran IV (Fortran 66 more
> or less) compilers. The first VAX compilers were Fortran 66, with
> the Fortran 77 compilers coming along a little later. It might be
> that the first ones ran in PDP-11 compatability mode.
>
> DEC had many extensions that IBM didn't have, ENCODE being one of them.
>
> (snip)
As I recall, there were 2 major incompatible versions of ENCODE among
the 3 brands of f66 compilers I used which supported that keyword. This
was one non-standard feature which went out of use rapidly when f77
compilers became available.
Actually where i use it is a bit more complex and not exactly
what you see here, and is related to Windows GUI builder where
utilizing Windows mouse realtime handling may cause
out-of-normal-order flow of the fortran code in callback
functions and its crash due to multiple internal writes could be
not completed and overlap in time.
So because I have to ask exactly what i need to make the request done
quick, my program-maximum is
integer foo
external foo
open(11,file='11.out')
open(12,file='12.out')
write(11,*) foo(12)
end
integer function foo(i)
character*9 char_I
write(char_i,'(i9)') i
write(12,*,err=1000) char_i
1000 foo=i
end
Or at least the code does not crash on internal write or internal
read (the program-minimum):
integer foo
external foo
open(11,file='11.out')
write(11,*) foo(12)
end
integer function foo(i)
character*9 char_I
write(char_i,'(i9)',err=1000) i
1000 foo=i
end
Or may be ask for implementing ENCODE/DECODE not via internal write?
Almost all compilers support it based on Polyhedron review.
Can i ask something else?
integer III
III = foo(12)
write(11,*) III
Unless you have lots and lots of writes with functions that do I/O in
the list, this looks like an easy fix.
Dick Hendrickson
I do not plan to switch compiler, right now it is just impossible,
because of specific to this compiler GUI builder i use. If company
make independent GUI builder like Winteracter, then yes,
you are right. But it is great compiler anyway. Very addictive btw,
so i am hooked up on its needle, unfortunately of not.
My problem is not fixable the way you have proposing unfortunately.
As i mentioned all things are done not exactly the way the examples
show it, they are just ultimate simplification.
Imagine there permanently go 5 I/O streams into 5 text windows and
several
graphics outputs. When you wiggle your mouse immediately starts
out-of-order call to callback function which handles mouse cursor
position and calculates (with internal file write) mouse
position numbers on the graphics screen plotting it there.
These I/O sometimes coincide with text I/O ----- booommm --- crash.
If I/O at least go to label if error occur - it would be a solution,
but it causes a crash.
May be there exist a way to implement something resembling ENCODE
- which transforms real or integer value into character
not via internal file write ?
>
> So because I have to ask exactly what i need, the program-maximum is
> (can i mask more?)
>
> integer foo
> external foo
>
> open(11,file='11.out')
> open(11,file='12.out')
> write(11,*) foo(12)
> end
>
> integer function foo(i)
> character*9 char_I
> write(char_i,'(i9)') i
> write(12,*,err=1000) char_i
> 1000 foo=i
> end
>
>
> Or at least the code does not crash on internal write or internal read
> (the program-minimum)
>
> integer foo
> external foo
>
> open(11,file='11.out')
> write(11,*) foo(12)
> end
>
> integer function foo(i)
> character*9 char_I
> write(char_i,'(i9)',err=1000) i
> 1000 foo=i
> end
>
> Or may be ask for implementing ENCODE/DECODE not via internal write?
> Almost all compilers support it based on Polyhedron review.
Your minimum version appears to be covered under f2003. It seems
unlikely that adding a 35-year backward looking extension would be as
promising as selected f2003 support.
You got the answers about how your maximum version was difficult to
implement and is not standard compliant.
> My minimum requirement is at least to make the code not
> crash,
There are compilers that detect the error at run-time, give an error
message, and abort. I'd guess that wouldn't be particularly difficult
for most compilers and seems pretty "nice". That *IS*, however, a
"crash" by some (most?) definitions; perhaps you mean something more
specific by "crash".
Note that if you expect compilers to keep your code from ever crashing
due to any user error, you are plain out of luck. For this error in
particular, you might fare better.
> The fact it works in some other compilers
> usually stimulates developers most.
Not in my observation. What stimulates developers most is that
influential customers (i.e. those with lots of money) insist on
something. Next most is probably that lots of customers ask for
something. If nothing else, fixing something that lots of people ask for
cuts support costs. Somewhere in the list is also conformance with
standards and other contractual requirements.
That something works with other compilers can be used to add support to
one of the other reasons, but doesn't tend to stand very well on its
own.
> So because I have to ask exactly what i need to make the request done
> quick,
The only realistic way to get your problem fixed quickly, you'll have to
fix your code. See Disk's or my suggestions on that.
As Dick mentioned, getting enhancement requests through compiler vendors
tends to be a slow process, even for high priority enhancements. In the
best cases, it takes months; on the order of a year is more realistic,
and it can easily be multiple years. You aren't going to get anything in
this area tagged as high enough priority to drive release schedules - no
matter what (unless perhaps you are sitting on a lot of money for it; a
few few million dollars would speak pretty loudly).
> Or at least the code does not crash on internal write or internal
> read (the program-minimum):
That one you have decent odds on at least being on the list, as
1. Lots of other people have asked for that one.
2. It is in the f2003 standard.
In fact, odds are that just waiting will get you that one in any
actively maintained compiler that doesn't already have it. But you still
won't get it nearly as quickly as fixing your code unless it is already
done in a compiler release about to come out.
> Or may be ask for implementing ENCODE/DECODE not via internal write?
As I mentioned before, that makes no sense. It is also
counter-productive.
1. Since there are no implementations that implement encode/decode via
internal write, asking for them not to do what they already don't do
isn't going to achieve much.
2. If you wanted encode/decode to work recursively, you would be better
advised to ask the opposite - that they be done using internal write,
because making internal write work recursively is already likely to be
at least somewhere on the vendor wish list.
3. You aren't going to have any luck asking for enhancements relating to
encode/decode anyway. Not going to happen.
4. And enhancement requests should pretty much never talk about how the
compiler implements things. They should talk about what the user wants
as capability. That's the case even if you have some clue about compiler
implementation internals - which clearly is not the case if you are
talking about "implementing encode/decode via internal write."
> May be there exist a way to implement something resembling ENCODE
> - which transforms real or integer value into character
> not via internal file write ?
Sure there is. That's the other posibility that I already mentioned in a
previous post. Not as a compiler feature - that isn't in the cards. Just
sit down and write out the algorithm just like you would any other. If
you want to handle subtle rounding issues and last-bit accuracy in
floatting point, that can be tricky.
But integer to character is trivial. One could bang that out in simple
standard Fortran in less time than has been spent on this thread - a ot
less. I used to have a function like that around. Let's see... Nah, I
don't have a general one around any more (I mostly use the aproach Dick
mentioned and avoid invoking such functions in I/O lists). But I do have
a special case done for one function where I found it worth the bother
to be able to use the finction directly in an IO list. The function
below references a few other things that you won't have, but you would
not be using this function directly as is anyway. It should be adequate
to illustrate the idea.
function time_string (time)
!-- Convert time to a string format for printing.
!-- 22 Jun 90, Richard Maine.
!-------------------- interface.
real(r_kind), intent(in) :: time
character :: time_string*12
!-------------------- local.
integer :: hmsms(4), i, j, divide, i_digit
character, parameter :: digit_chars(0:9) = &
(/ '0','1','2','3','4','5','6','7','8','9'/)
character :: hmsms_strings(4)*3
!-------------------- executable code.
call time_to_hmsms(time, hmsms)
!-- The rest of this subroutine is a long-winded equivalent of the
!-- following commented-out internal write. The long way is
!-- used so that this function can be referenced in an output
!-- iolist without violating the ansi restriction on the use of
!-- io statements in such functions.
!-- write (time_string,'(2(i2.2,1h.),i2.2,1h.,i3.3)') hmsms
do i = 1 , 4
divide = 1000
do j = 1 , 3
i_digit = abs(mod(hmsms(i),divide))
divide = divide/10
i_digit = i_digit/divide
hmsms_strings(i)(j:j) = digit_chars(i_digit)
end do
end do
if (hmsms(1) > 99 .or. hmsms(1) < 0) hmsms_strings(1)='***'
time_string = hmsms_strings(1)(2:3) // '.' // hmsms_strings(2)(2:3)
&
// '.' // hmsms_strings(3)(2:3) // '.' // hmsms_strings(4)
return
end function time_string
Aren't my examples which write NOT IN THE SAME UNIT but into two
different I/O using have to be allowed?
> On Dec 21, 2:55 am, robert.corb...@sun.com wrote:
> > Sun Fortran has allowed "recursive" I/O involving
> > different I/O units since the 2.0 release of Sun f90.
> > It was hard to implement, but it was well worth the
> > effort.
> >
> > Allowing recursive I/O to the same unit is an often
> > requested extension, but it is problematic.
>
> Aren't my examples which write NOT IN THE SAME UNIT but into two
> different I/O using have to be allowed?
I'm having trouble parsing "Aren't my examples... have to be allowed?"
See Bob's first sentence. They are allowed in Sun f90 as of its release
2.0. That's exactly what he said. If "have to be allowed" means
something else, I'm not following it. No the standard doesn't say that
they have to be allowed, if that's perhaps the intended meaning.
>
> Well, ENCODE was in the PDP-10 and PDP-11 Fortran IV (Fortran 66 more
> or less) compilers. The first VAX compilers were Fortran 66, with
> the Fortran 77 compilers coming along a little later. It might be
> that the first ones ran in PDP-11 compatability mode.
>
> DEC had many extensions that IBM didn't have, ENCODE being one of them.
>
> (snip)
>
Yes. The BMD programs, rescued in their modified source from the old
DEC library, usually contained the ENCODE function (easy to replace)
and also the use of a special DEC version of SIGN (used to mark a
blank entry as -0) which was NOT easy to replace and needed a complete
replacement of the read statements with a subroutine call that first
had to map the input field set from the format statement.
Life would have been easier for this person, if the University of Los
Angeles handn't dumped the original public domain source, in favour of
the licensed BMDP versions. I even went their library stacks to seek
them.
> So because I have to ask exactly what i need, the program-maximum is
> (can i mask more?)
> integer foo
> external foo
> open(11,file='11.out')
> open(11,file='12.out')
> write(11,*) foo(12)
> end
> integer function foo(i)
> character*9 char_I
> write(char_i,'(i9)') i
> write(12,*,err=1000) char_i
> 1000 foo=i
> end
I had this problem with recursive I/O when I wrote a code generator
and posted it to the web so people could test it. It seemed
illogical to me that f90 allowed the programmer to write recursive
code but that f95 permitted compilers to implement I/O, even
internal I/O, via fixed data structures that made all I/O operations
non-reentrant.
But if my code was going to be generally usable I had to modify my
code. What I did was to create functions that could compose strings
from numbers using specification functions to determine their LENs.
Then I could compose a line of output via concatenation of several
such strings (function results) and invoke a subroutine to print
out a line of output. Worked really well except that some f95
compilers had problems with the specification functions or in
general with complicated specification expressions. Here is an
example adapted to your program:
C:\gfortran\clf\recursive_io>type recursive_io.f90
module stuff
implicit none
contains
subroutine write_unit(iunit,x)
integer, intent(in) :: iunit
character(*), intent(in) :: x
write(iunit,'(a)') x
end subroutine write_unit
function compose_i4(x)
integer, intent(in) :: x
character(compose_i4_len(x)) compose_i4
write(compose_i4,*) x
end function compose_i4
pure function compose_i4_len(x)
integer compose_i4_len
integer, intent(in) :: x
character(range(x)+3) temp
write(temp,*) x
compose_i4_len = len_trim(temp)
end function compose_i4_len
end module stuff
program test
use stuff
implicit none
integer foo
external foo
open(11,file='11.out')
! open(11,file='12.out') ! BUG!
open(12,file='12.out')
! write(11,*) foo(12)
call write_unit(11,compose_i4(foo(12)))
end program test
integer function foo(i)
implicit none
integer i
character*9 char_I
write(char_i,'(i9)') i
write(12,*,err=1000) char_i
1000 foo=i
end function foo
C:\gfortran\clf\recursive_io>gfortran -Wall recursive_io.f90 -orecursive_io
C:\gfortran\clf\recursive_io>recursive_io
C:\gfortran\clf\recursive_io>type 11.out
12
C:\gfortran\clf\recursive_io>type 12.out
12
For a more complex example, consider the usage of subroutine WX
in http://home.comcast.net/~kmbtib/conv2c.f90 .
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
> ...the University of Los Angeles
Ain't no such animal. I assume you are probably referring to the
University of California, Los Angeles (which I have a few degrees from).
There is also California State University, Los Angeles (where 2 of my
kids went for a while). And Google remids me that there is a City
University Los Angeles. Thought I would check Google before posting just
in case there happened to actually be a school by that name that I'd
never heard of.
Yes, the last option I meant, trying to say that all my examples
have to be allowed by the standard : looks like it's nothing wrong
with writing into different I/O unit but of course i may miss
some pitfalls. Would appreciate killing this idea
reasons since i plan to suggest to developers to
consider this as an extension, all compilers have many thousands
of them, this compiler specifically
As to your suggestion and encouragement to write own
character <-> real/integer conversion utility -
yep, this is great, it is probably the only what is left as a
quick option.
Unless may be if someone will find some the time and send me a
DLL made in their compiler which supports just these two
old functions encode and decode...will be great if they are
not conflicting with the I/O
It seems that way, but it really shouldn't be so much of a problem
in most cases. I was thinking that the problem goes back to Fortran II,
but even in Fortran 66 you can't have function calls in I/O statements.
Probably the most common extension to Fortran 66 allows expressions
in subscripts, instead of the restricted subscripts allowed by the
standard. In that case, you could have function calls in subscripts,
but not as I/O list elements.
I believe, at least at the time, my favorite addition in Fortran 77
was allowing expressions in the I/O list of WRITE statements. So many
temporary variables used to be needed.
So, why didn't they fix this with Fortran 90? I would guess that
there were already so many other things being added that it was
decided that this wasn't really needed.
> But if my code was going to be generally usable I had to modify my
> code. What I did was to create functions that could compose strings
> from numbers using specification functions to determine their LENs.
> Then I could compose a line of output via concatenation of several
> such strings (function results) and invoke a subroutine to print
> out a line of output. Worked really well except that some f95
> compilers had problems with the specification functions or in
> general with complicated specification expressions. Here is an
> example adapted to your program:
(snip)
I would have thought it easier to remove function calls from I/O
lists, and use temporary variables to store the value. Though
complicated by not knowing the length in advance, and no
non-advancing I/O.
-- glen
Thanks for the example. Just report immediate error without looking
inside to fix that : "attempt to write past end of internal file"
I did not get though your idea as soon as i see killing it
write(iunit,'(a)') x
This compiler does not allow recursive I/O was it real I/O or internal
file I/O
Partly, it's because it's really hard to figure out all of the cases.
We've been looking at a simple write(11,*) f(x) example. But, for more
complicated formats, with nested parenthesis and repeat counts and tabs
and : and whatever else, there's a lot of internal library state to save
and interactions to consider. What happens if f(x) rewinds 11? Or does
a backwards tab? Or does a reopen that changes a mode like blank=? Or
in read(11,11) f(x) suppose f does a write to 11. It's not that you
can't come up with an answer to the questions (mostly it's "you can't do
that"), it's that there's a lot of them.
Second, converting library routines to do recursive I/O requires some
significant work and potentially slows down I/O.
So, you mostly answered your question. The demand for recursive I/O was
believed to be generally low and not worth the cost.
Dick Hendrickson
It wasn't a problem, because recursive I/O and recursion were done in PL/I in 1966.
> 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.
It isn't a problem, because it was done in PL/I back in 1966.
And what compiler is that? F77?
>
> 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".
That's because it is recursive 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.
It requires recursion, not multithreading.
Why not change FOO to a subroutine?
Then you don't have that problem.
in mulththreading we have special lock mechanism which
allows I/O even on the same unit, if you lock
it until it finishes its work, then unlock. Another
I/O will then safely come so two overlapping in time
I/Os will not conflict. That is one more option i
reluctantly pursue now...
All that complex cases with rewinds, backward tabs and whatever
are irrelevant to the case where two independent I/O units were
open like in my example.
> Thanks for the example. Just report immediate error without looking
> inside to fix that : "attempt to write past end of internal file"
I didn't take into account how perverse the compiler could be in its
implementation of list-directed I/O. If it inserts a large number of
leading spaces or any trailing spaces it will break my example.
Therefore we have to jettison list-directed I/O in favor of minimal
field width output:
C:\gfortran\clf\recursive_io>type recursive_io2.f90
module stuff
implicit none
contains
subroutine write_unit(iunit,x)
integer, intent(in) :: iunit
character(*), intent(in) :: x
write(iunit,'(a)') x
end subroutine write_unit
function compose_i4(x)
integer, intent(in) :: x
character(compose_i4_len(x)) compose_i4
write(compose_i4,'(i0)') x
end function compose_i4
pure function compose_i4_len(x)
integer compose_i4_len
integer, intent(in) :: x
character(range(x)+2) temp
write(temp,'(i0)') x
compose_i4_len = len_trim(temp)
end function compose_i4_len
end module stuff
program test
use stuff
implicit none
integer foo
external foo
open(11,file='11.out')
! open(11,file='12.out') ! BUG!
open(12,file='12.out')
! write(11,*) foo(12)
call write_unit(11,compose_i4(foo(12)))
end program test
integer function foo(i)
implicit none
integer i
character*9 char_I
write(char_i,'(i9)') i
write(12,*,err=1000) char_i
1000 foo=i
end function foo
C:\gfortran\clf\recursive_io>gfortran -Wall
recursive_io2.f90 -orecursive_io2
C:\gfortran\clf\recursive_io>recursive_io2
C:\gfortran\clf\recursive_io>type 11.out
12
C:\gfortran\clf\recursive_io>type 12.out
12
> I did not get though your idea as soon as i see killing it
> write(iunit,'(a)') x
Unfortunate that you didn't proofread before posting. I can't
even guess at what the above paragraph is supposed to mean.
> This compiler does not allow recursive I/O was it real I/O or internal
> file I/O
The whole point of my technique is that no recursive I/O remains.
Try it again with the revised version. Maybe your compiler is one
of those that has problems with complicated specification expressions.
What compiler and version is it?
> I had this problem with recursive I/O when I wrote a code generator
> and posted it to the web so people could test it. It seemed
> illogical to me that f90 allowed the programmer to write recursive
> code but that f95 permitted compilers to implement I/O, even
> internal I/O, via fixed data structures that made all I/O operations
> non-reentrant.
There is no connection between recursive I/O and recursion.
None of the Fortran implementations I have used that support
recursive I/O use recursion in their implementations of
recursive I/O.
Bob Corbett
With latest changes your example works, so i've got the trick you do.
Unfortunately do not see how can i use it to fool the compiler
not to crash, since i've mentioned already that the crash i get has
most probably different origin then my recursive I/O examples above.
I suspect it crashes because of write somewhere in the code
( i have several Windows screens and I/O streams open) coincides
with another read/write caused by mouse movements. The flood of mouse
position changes causes flood of started
callbacks (with their internal file writes) and they
overlap in time with those which print something into my open
windows.
Thanks for the pure elemental equilibristics though.
Compiler is FTN95 of Silverfrost.
Well, no, except that both require reentrancy.
I suppose reentrant I/O would be a better term, but it doesn't
seem to be the one people use.
-- glen
Well, no, they certainly don't HAVE to be allowed, considering that at
the present time, they are NOT allowed.
If you would like to see that changed, the most productive way to
accomplish that is probably to write a proposal to change the standard
to allow it. A good proposal would take into account all of the various
ways such an allowance would affect the language, including interaction
with other features that you may not have considered. If you have a
good proposal, then you would also need to find someone who goes to the
standards meetings to champion the proposal, but I think it would be
more difficult to write a good proposal than, having written one, to
find someone willing to try to shepherd it.
>May be there exist a way to implement something resembling ENCODE
>- which transforms real or integer value into character
>not via internal file write ?
Of course there is, and it's easy enough to do it yourself.
Converting to integer has been published quite some time ago.
>> It requires recursion, not multithreading.
>
>> Why not change FOO to a subroutine?
>> Then you don't have that problem.
>in mulththreading we have special lock mechanism which
>allows I/O even on the same unit, if you lock
>it until it finishes its work, then unlock.
Requires multiple copies of the code.
Or requires recursive code.
Then there's the question of I/O buffers.
> Another
>I/O will then safely come so two overlapping in time
>I/Os will not conflict. That is one more option i
>reluctantly pursue now...
Why not change FOO to a subroutine?
>Thanks to all for discussions. I plan to request from my Fortran 95
>compiler developers to address this issue at least as an extension, so
>what specifically i have to ask as program-minimum and program-
>maximum? My minimum requirement is at least to make the code not
>crash, this is totally disgusting and DOS-ish. To make my request
>completely focused and more solid please check these two snippets
>work. The fact it works in some other compilers usually stimulates
>developers most.
>
>Actually where i use it is a bit more complex and not exactly what you
>see here, and is related to Windows GUI builder where utilizing
>Windows mouse realtime handling may cause out-of-normal-order flow of
>the fortran code in callback functions and its crash due to multiple
>internal writes could be not completed and overlap in time. Result is
>a crash. Yuck.
>
>So because I have to ask exactly what i need, the program-maximum is
>(can i mask more?)
>
> integer foo
> external foo
>
> open(11,file='11.out')
> open(11,file='12.out')
> write(11,*) foo(12)
> end
>
> integer function foo(i)
> character*9 char_I
> write(char_i,'(i9)') i
> write(12,*,err=1000) char_i
>1000 foo=i
> end
>
>
>Or at least the code does not crash on internal write or internal read
>(the program-minimum)
>
> integer foo
> external foo
>
> open(11,file='11.out')
> write(11,*) foo(12)
> end
>
> integer function foo(i)
> character*9 char_I
> write(char_i,'(i9)',err=1000) i
>1000 foo=i
> end
>
>Or may be ask for implementing ENCODE/DECODE not via internal write?
>Almost all compilers support it based on Polyhedron review.
No-one's going to implement non-standard ENCODE/DECODE which became
redundant with F77 -- that's 30 years ago.
>Aren't my examples which write NOT IN THE SAME UNIT but into two
>different I/O using have to be allowed?
Requires recursive I/O, as many have already said.
That may be so, but it isn't the reason.