Hi,
I've written a small file copy routine for text files. The problem I
have is that sometimes the final of the line is copied twice and
sometimes only once. I can't quite figure out why the final line is
being copied inconsistently. Usually, it is copied twice however, which
is preferable to having the final line not copied. Can anyone spot the
problem, or is it just one of those problems I have to live with?
Any other comments on improving my subroutine are welcome also.
Thanks,
John
module copy_file
implicit none
contains
!=======================================================================
subroutine copy(oname,nname,max_line_length)
implicit none
character (len=*), intent(in) :: oname
character (len=*), intent(in) :: nname
integer, intent(in) :: max_line_length
character (len=max_line_length) :: line
integer, parameter :: F_TMP_ = 20
integer, parameter :: F_TMP1_ = 21
integer :: astat,rstat,wstat,nchars,tl
logical :: ex
inquire(file=oname,exist=ex) ; if (.not. ex) return
if (adjustl(oname) .eq. adjustl(nname)) &
call error('old file name and new file name are the same')
open(unit=F_TMP_ ,file=oname,status='old' ,iostat=astat)
call chkstatf(astat,oname)
open(unit=F_TMP1_,file=nname,status='unknown',iostat=astat)
call chkstatf(astat,nname)
astat = 0
rstat = 0
wstat = 0
do while (rstat .eq. 0 .and. wstat .eq. 0)
read (F_TMP_,fmt='(A)',advance='no',size=nchars, &
iostat=rstat,err=502,end=501,eor=500) line
call error('error copying file occured')
! the end of the record was reached, print line
500 tl = min( index(line,char(10)), index(line,char(13)) )
if(tl .eq. 0) tl = len(line)+1
write(F_TMP1_,fmt='(A)',iostat=wstat,err=502) trim(line(:tl-1))
rstat = 0 !we need to reset
end do
!this sometimes results in the last line being copied twice (why only
sometimes?)
!the end of the file was reached, print last line
501 tl = min( index(line,char(10)), index(line,char(13)) )
if(tl .eq. 0) tl = len(line)+1
write(F_TMP1_,fmt='(A)',iostat=wstat,err=502) trim(line(:tl-1))
close(F_TMP_ ,iostat=astat) ; call chkstatf(astat,oname)
close(F_TMP1_,iostat=astat) ; call chkstatf(astat,nname)
return
!an error occured
502 call error('error copying file occured')
end subroutine copy
!=======================================================================
subroutine error(message)
implicit none
character (len=*), intent(in) :: message
write(*,*) message
stop
end subroutine error
!=======================================================================
subroutine chkstatf(astat,fname)
implicit none
integer, intent(in) :: astat
character (len=*), intent(in) :: fname
if (astat.ne.0) then
write(*,*) 'FILE ERROR - ', fname
stop
end if
end subroutine chkstatf
!=======================================================================
end module copy_file
|
|
0
|
|
|
|
Reply
|
gh14tq5 (118)
|
5/17/2008 1:37:11 AM |
|
John <gh14tq5@yahoo.com> wrote:
> I've written a small file copy routine for text files. The problem I
> have is that sometimes the final of the line is copied twice and
> sometimes only once. I can't quite figure out why the final line is
> being copied inconsistently. Usually, it is copied twice however, which
> is preferable to having the final line not copied. Can anyone spot the
> problem, or is it just one of those problems I have to live with?
>
> Any other comments on improving my subroutine are welcome also.
I personally find usage of err=, end=, and eor= hard to follow because
of the way they jump around. Not just your code in particular, but those
features in general. I tend to prefer using iostat= and testing the
value. That's just my personal style preference, though.
> do while (rstat .eq. 0 .and. wstat .eq. 0)
I also tend to find that particular style of DO while confusing. I know
it is popular in some circles, but as soon as I see it, I begin to
wonder whether all the variables involved are always set appropriately
or whether there might be some edge case that they miss. I prefer a
simple DO with eit statements. Again, that's a personal style
preference. Nothing actually wrong here. Feel free to ignore my comment.
> read (F_TMP_,fmt='(A)',advance='no',size=nchars, &
> iostat=rstat,err=502,end=501,eor=500) line
> call error('error copying file occured')
Something odd here. You call error if there are is no error or eor? I
suppose that perhaps you consider not hitting an eor to be an error. I
guess that sort of makes sense, but it just looks odd to me.
>
> ! the end of the record was reached, print line
> 500 tl = min( index(line,char(10)), index(line,char(13)) )
The line string "shouldn't" include any cr or lf characters (char(13)
and char(10)). But then, I suppose it could happen if the file had
different record terminators than the normal ones for your OS. I guess
the test doesn't hurt anyway and might catch odd cases.
> if(tl .eq. 0) tl = len(line)+1
>
> write(F_TMP1_,fmt='(A)',iostat=wstat,err=502) trim(line(:tl-1))
> rstat = 0 !we need to reset
> end do
>
> !this sometimes results in the last line being copied twice (why only
> sometimes?)
>
> !the end of the file was reached, print last line
>
> 501 tl = min( index(line,char(10)), index(line,char(13)) )
This might be part of your problem. You go here on an end=. After
hitting an end=, the value of anything in th eiolist (namely line) is
undefined. This means that it is illegal to reference it, as you do
here. If you do reference it, the results are unpredictable and might
well depend on various factors.
For example, I might well suspect that the results would vary depending
on whether or not the last line in the input file was properly
terminated. I suspect this is reasonably likely to be the problem area.
--
Richard Maine | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle | -- Mark Twain
|
|
0
|
|
|
|
Reply
|
nospam47 (9742)
|
5/17/2008 2:22:52 AM
|
|
Richard Maine wrote:
> I personally find usage of err=, end=, and eor= hard to follow because
> of the way they jump around. Not just your code in particular, but those
> features in general. I tend to prefer using iostat= and testing the
> value. That's just my personal style preference, though.
Some of us spent some effort putting automatic conversion of err= ,end=
into iostat= with IF..ELSE blocks in our Fortran reformatters, back in the
days when f77 was relatively new.
I am humbled a bit by finding that my web search skills aren't adequate to
turn up examples of this recommendation, though I did turn up plenty of
evidence in favor.
I have to wonder if people use iostat= and err= together (not only in
gfortran testsuite) in order to break automatic reformatting scripts.
|
|
0
|
|
|
|
Reply
|
tprince (585)
|
5/17/2008 6:21:33 AM
|
|
Richard Maine wrote:
> John <gh14tq5@yahoo.com> wrote:
>
>> I've written a small file copy routine for text files. The problem I
>> have is that sometimes the final of the line is copied twice and
>> sometimes only once. I can't quite figure out why the final line is
>> being copied inconsistently. Usually, it is copied twice however, which
>> is preferable to having the final line not copied. Can anyone spot the
>> problem, or is it just one of those problems I have to live with?
>>
>> Any other comments on improving my subroutine are welcome also.
>
> I personally find usage of err=, end=, and eor= hard to follow because
> of the way they jump around. Not just your code in particular, but those
> features in general. I tend to prefer using iostat= and testing the
> value. That's just my personal style preference, though.
>
>> do while (rstat .eq. 0 .and. wstat .eq. 0)
>
> I also tend to find that particular style of DO while confusing. I know
> it is popular in some circles, but as soon as I see it, I begin to
> wonder whether all the variables involved are always set appropriately
> or whether there might be some edge case that they miss. I prefer a
> simple DO with eit statements. Again, that's a personal style
> preference. Nothing actually wrong here. Feel free to ignore my comment.
>
>> read (F_TMP_,fmt='(A)',advance='no',size=nchars, &
>> iostat=rstat,err=502,end=501,eor=500) line
>> call error('error copying file occured')
>
> Something odd here. You call error if there are is no error or eor? I
> suppose that perhaps you consider not hitting an eor to be an error. I
> guess that sort of makes sense, but it just looks odd to me.
>
>> ! the end of the record was reached, print line
>> 500 tl = min( index(line,char(10)), index(line,char(13)) )
>
> The line string "shouldn't" include any cr or lf characters (char(13)
> and char(10)). But then, I suppose it could happen if the file had
> different record terminators than the normal ones for your OS. I guess
> the test doesn't hurt anyway and might catch odd cases.
>
>> if(tl .eq. 0) tl = len(line)+1
>>
>> write(F_TMP1_,fmt='(A)',iostat=wstat,err=502) trim(line(:tl-1))
>> rstat = 0 !we need to reset
>> end do
>>
>> !this sometimes results in the last line being copied twice (why only
>> sometimes?)
>>
>> !the end of the file was reached, print last line
>>
>> 501 tl = min( index(line,char(10)), index(line,char(13)) )
>
> This might be part of your problem. You go here on an end=. After
> hitting an end=, the value of anything in th eiolist (namely line) is
> undefined. This means that it is illegal to reference it, as you do
> here. If you do reference it, the results are unpredictable and might
> well depend on various factors.
>
> For example, I might well suspect that the results would vary depending
> on whether or not the last line in the input file was properly
> terminated. I suspect this is reasonably likely to be the problem area.
>
>
> I personally find usage of err=, end=, and eor= hard to follow because
> of the way they jump around. Not just your code in particular, but those
> features in general. I tend to prefer using iostat= and testing the
> value. That's just my personal style preference, though.
I will rewrite this and see which one I like better. I guess I was
using the jumps so I would not have to look up the iostat codes. Are
the iostat portable. I seem to recall that the sign was the main
indicator and not necessarily the number (which differ from compiler to
compiler). In that case, it doesn't like there would be enough
information to tell between err, end, eor.
>
>> do while (rstat .eq. 0 .and. wstat .eq. 0)
>
> I also tend to find that particular style of DO while confusing. I know
> it is popular in some circles, but as soon as I see it, I begin to
> wonder whether all the variables involved are always set appropriately
> or whether there might be some edge case that they miss. I prefer a
> simple DO with eit statements. Again, that's a personal style
> preference. Nothing actually wrong here. Feel free to ignore my comment.
>
I agree with you about this. It's been a while since I wrote this, and
even I had to think about the logic. I will probably change to exit
statements.
>> read (F_TMP_,fmt='(A)',advance='no',size=nchars, &
>> iostat=rstat,err=502,end=501,eor=500) line
>> call error('error copying file occured')
>
> Something odd here. You call error if there are is no error or eor? I
> suppose that perhaps you consider not hitting an eor to be an error. I
> guess that sort of makes sense, but it just looks odd to me.
>
Yes, when I wrote this, I assumed that the maximum possible line length
in the file would be passed as an argument. So, if I made it to the
line after the read, then something must have occurred. Maybe I should
try to rewrite the routine to take any length of line. I will have to
think about this.
>> ! the end of the record was reached, print line
>> 500 tl = min( index(line,char(10)), index(line,char(13)) )
>
> The line string "shouldn't" include any cr or lf characters (char(13)
> and char(10)). But then, I suppose it could happen if the file had
> different record terminators than the normal ones for your OS. I guess
> the test doesn't hurt anyway and might catch odd cases.
I wrote this routine in WinXP using cygwin. Maybe that was why the CR
and LF were showing up. To be honest, it's been a while since I wrote
the routine, so I will have to go back and check about the reason for this.
> This might be part of your problem. You go here on an end=. After
> hitting an end=, the value of anything in th eiolist (namely line) is
> undefined. This means that it is illegal to reference it, as you do
> here. If you do reference it, the results are unpredictable and might
> well depend on various factors.
>
> For example, I might well suspect that the results would vary depending
> on whether or not the last line in the input file was properly
> terminated. I suspect this is reasonably likely to be the problem area.
This is good to know. I suspect this is probably the reason. I will
try to check a few files and see.
Thanks for your suggestions. Hopefully, I can improve my routine a
little bit.
John
|
|
0
|
|
|
|
Reply
|
gh14tq5 (118)
|
5/17/2008 7:22:47 AM
|
|
John <gh14tq5@yahoo.com> wrote:
> Richard Maine wrote:
> > I personally find usage of err=, end=, and eor= hard to follow because
> > of the way they jump around. Not just your code in particular, but those
> > features in general. I tend to prefer using iostat= and testing the
> > value. That's just my personal style preference, though.
>
> I will rewrite this and see which one I like better. I guess I was
> using the jumps so I would not have to look up the iostat codes. Are
> the iostat portable. I seem to recall that the sign was the main
> indicator and not necessarily the number (which differ from compiler to
> compiler). In that case, it doesn't like there would be enough
> information to tell between err, end, eor.
That's a good point. You can distinguish between err and the others by
the sign. But you can't easily and portably distinguish between end and
eor. (You can do it either easily or portably, but not both). I rarely
need to do that, but in contexts where you would need to, I'll grant the
point. F2003 provides an easy portable way to distinguish, but f90/f95
don't.
--
Richard Maine | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle | -- Mark Twain
|
|
0
|
|
|
|
Reply
|
nospam47 (9742)
|
5/17/2008 2:13:54 PM
|
|
John wrote:
> Richard Maine wrote:
....
>> I personally find usage of err=, end=, and eor= hard to follow
>> because of the way they jump around. Not just your code in
>> particular, but those features in general. I tend to prefer using
>> iostat= and testing the value. That's just my personal style
>> preference, though.
>
> I will rewrite this and see which one I like better. I guess I was
> using the jumps so I would not have to look up the iostat codes. Are
> the iostat portable. I seem to recall that the sign was the main
> indicator and not necessarily the number (which differ from compiler
> to compiler). In that case, it doesn't like there would be enough
> information to tell between err, end, eor.
Like in most cases there is no "one size fits all" for style. In this
case what is more natural depends on the meaning of errors or
end of file conditioons in your program. If an error or an end of
file is something that you regard as fatal to the process, then you
should probably use err= or end= instead of iostat. On the other
hand, if an error or end of file is normal and part of what you usually
expect, you should use iostat.
Here you have both. Any I/O errors cause you to halt the copy
sequence prematurely. At present what you do is write an error
and return from the copy subroutine. However, you do quite
correctly have the handler for this exceptional condition removed
to the bottom of the code separate from normal control flow.
However, the end of file condition is something you seem to
consider normal and indeed it is part of your your loop termination
condition. you really shouldn't use end= in such a case. However,
you also regard end of record peculiarly (apparently you regard a
record longer than your LINE buffer as erroneous, even though
you are using non-advancing I/O and can handle such records).
I'd have to understand more clearly what you really intend before
I could comment on that convolution of your code.
>>> do while (rstat .eq. 0 .and. wstat .eq. 0)
>>
>> I also tend to find that particular style of DO while confusing. I
>> know it is popular in some circles, but as soon as I see it, I begin
>> to wonder whether all the variables involved are always set
>> appropriately or whether there might be some edge case that they
>> miss. I prefer a simple DO with eit statements. Again, that's a
>> personal style preference. Nothing actually wrong here. Feel free to
>> ignore my comment.
>
> I agree with you about this. It's been a while since I wrote this, and
> even I had to think about the logic. I will probably change to exit
> statements.
I actually don't even understand Maine's point here. I know that some
people are more comfortable with expressing the reason to leave in
a positive sense and would prefer an UNTIL clause. I know that
some people prefer to express the reason to stay in the loop in the
positive sense and therefore prefer WHILE. However, it's not been
my experience that in languages that provide both that either one is
more error prone than the other. It seems to me that mistakes about
"edge cases" and such are about similarly common with both
styles. (WHILE was rather in vogue a few decades back among
some formalists. The idea was that the WHILE condition was
that part of your loop invariant that became false when you were
finished with the loop. Yeah... well I didn't quite buy it either.)
However, Fortran doesn't have UNTIL and only has WHILE as a
clause of the DO statement. Instead, it has the EXIT statement, which
is almost always to be avoided if at all possible. If you can't manage
to get your loop test to the top of the loop, or if you can't manage to
have only one condition that needs testing, you may be stuck with
EXIT. If you can at all manage to make your test at the start of the
loop, a WHILE clause is probably better. (It really would be nice
to have both WHILE and UNTIL as statements that can appear
anywhere in the loop.)
The problem with EXIT is twofold. First: all the control statements
that are part of a given control construct are best kept at the same
nexting level as the construct they are part of. Unfortunately, EXIT
is *always* inside a further nested conditional (an IF or CASE).
This makes the second part hard to manage. Second: all the control
statements that are part of a given control construct should be on
the left of the line containing them, and indented to the same degree
as the statements that delimit the beginning and end of that construct.
Since EXIT is always embedded within some conditional, you
always have to do some peculiar formatting to make it show on
the left of a line and be indented the same as the corresponding
DO and END DO statements.
--
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
|
|
0
|
|
|
|
Reply
|
jamesgiles (2210)
|
5/17/2008 5:46:37 PM
|
|
James Giles <jamesgiles@worldnet.att.net> wrote:
> > Richard Maine wrote:
> >>> do while (rstat .eq. 0 .and. wstat .eq. 0)
> >>
> >> I also tend to find that particular style of DO while confusing....
> I actually don't even understand Maine's point here. I know that some
> people are more comfortable with expressing the reason to leave in
> a positive sense and would prefer an UNTIL clause.
No. My point is nothing to do with that. It is more that the loop
condition is one place, but the variables that control it are defined
elsewhere. It is that separation that makes it hard to read for me. An
UNTIL would be just as bad because it still isn't particularly near to
where the relevant variables get defined.
Basically, I look at the above line of code and it tells me very little.
I see that the loop will end when either of the variables named rstat
and wstat become non-zero. But how does that happen? Will it happen
reliably or are there cases where they might not get set as desired? Are
they initialized appropriately in the first place? I have to look
elsewhere for the answers to all those questions. I have to check all
the places that rstat and wstat might get set; and whenever I see a
place where they are set, I have to think about the consequences to the
loop.
In fact, that very specifically happened to me when reading this
particular code. I was reading it sequentially, and when I came to that
line, I had not yet seen any of the code that sets the values. So I had
to mentally flag it as "here's a loop that I don't yet understand the
exit coditions for; I'll have to watch for that and make sure they are
ok." This isn't some abstract judgement about general loops. This is a
confusion that specifically did happen to me as I was reading this exact
code. So I absolutely know that this style *DOES* cause confusion, at
least with me. Perhaps it is only me.... but I doubt it.
> The problem with EXIT is twofold. First: all the control statements
> that are part of a given control construct are best kept at the same
> nexting level as the construct they are part of.
That's exactly what I disagree with. I like the fact that with EXIT the
loop control can be exactly where the relevant data becomes available. I
don't want it separated and put with the statements at the beginning or
end of the loop. When I decide that it is time to exit the loop, I can
simply say so right there. Without EXIT, I end up instead setting some
variable, which is tested elsewhere. I just find
if (some_condition) EXIT do_loop
to be incredibly easier to read and follow than, say
if (some_condition) need_to_exit = .true.
and somewhere possibly far separated, we fond out that need_to_exit
controls exiting from the loop. I'm not even counting the extra logic
needed to skip to the end of the loop if the exit condition got set in
the middle of the loop and the rest of that loop pass needs to be
skiped, as is the case in a large majority of my loops, particular ones
involving I/O as in this case.
That separation is my big gripe. When we see that the READ statement
sets rstat, there is nothing directly there to tell us that this is
going to cause a loop exit somewhere or other. We have to either
remember (if it was a DO WHILE) or look forward (with DO UNTIL) to
notice that. I find that separation to be hugely more confusing than the
issues of wanting to find the EXIT statement within a loop. Again, yes
it *IS* harder for me to follow. Not that it might be in principle; it
in fact is harder for me based on first-hand observation (including the
exact case at hand).
But I'm pretty sure that you won't find this convincing, so I'll not
argue it with further posts. I do find my personal experience to be far
more convincing to me than 3rd-party studies or abstract notions of what
ought to be better, so quoting such studies or notions won't be very
convincing to me. I'll just say that in advance so that I don't feel
obligated to prolong the discussion by saying that later.
The above business about the setting of the relevant variables being
separated from their use in loop control is just my attempt at
self-analysis of why I find forms with EXIT so much more clear. Maybe my
analysis is wrong and it is just all because my mind works strangely.
But for whatever reason, the EXIT forms are more clear to me (when well
done; of course, any form can be abused and made confusing).
--
Richard Maine | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle | -- Mark Twain
|
|
0
|
|
|
|
Reply
|
nospam47 (9742)
|
5/17/2008 6:57:52 PM
|
|
Richard Maine wrote:
> James Giles <jamesgiles@worldnet.att.net> wrote:
....
>> The problem with EXIT is twofold. First: all the control statements
>> that are part of a given control construct are best kept at the same
>> nexting level as the construct they are part of.
>
> That's exactly what I disagree with. I like the fact that with EXIT
> the loop control can be exactly where the relevant data becomes
> available. I don't want it separated and put with the statements at
> the beginning or end of the loop. When I decide that it is time to
> exit the loop, I can simply say so right there. Without EXIT, I end
> up instead setting some variable, which is tested elsewhere. I just
> find
>
> if (some_condition) EXIT do_loop
>
> to be incredibly easier to read and follow than, say
>
> if (some_condition) need_to_exit = .true.
But:
UNTIL(some_condition)
is vastly easier to read then either. Notice that since it's
part of the loop construct, it can be indented to the same level
as the corresponding DO and END DO, and that the fact that
it's a loop control is explicitly visible as the first token of the line.
Bot the IF forms might just be *any* conditional test within
the loop. You have to read the whole line to find that it's
really part of the loop construct.
To get EXIT to line up witt the corresponding DO and END DO
is really a pain. If find that having to pick trough every statement
of a loop in order to find those statements that are actually an inherent
part of the looping construct itself to be really irritating. Further
I would regard a branch that crosses more than one level of nested
constructs as inherently unstructured, yet EXIT must *always*
do so.
--
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
|
|
0
|
|
|
|
Reply
|
jamesgiles (2210)
|
5/17/2008 7:16:05 PM
|
|
Richard Maine wrote:
> James Giles <jamesgiles@worldnet.att.net> wrote:
>
>>> Richard Maine wrote:
>
>>>>> do while (rstat .eq. 0 .and. wstat .eq. 0)
>>>>
>>>> I also tend to find that particular style of DO while confusing....
>
>> I actually don't even understand Maine's point here. I know that
>> some people are more comfortable with expressing the reason to leave
>> in
>> a positive sense and would prefer an UNTIL clause.
>
> No. My point is nothing to do with that. It is more that the loop
> condition is one place, but the variables that control it are defined
> elsewhere. [...]
I forgot to respond to this part. My point was that if the loop test
is at the top of the loop, then you're always better off with a WHILE
than an IF-EXIT. I even pointed out explicitly that there are a
number of reasons that the loop test can't be at the top, or shouldn't
be. I alread statedy (clearly) in the article to which you responded
that in such case you have no choice but to use EXIT since Fortran
provides nothing else. :-(
The rest of my article was motivation to the style decision that
not using EXIT, if at all possible, was always to be preferred.
--
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
|
|
0
|
|
|
|
Reply
|
jamesgiles (2210)
|
5/17/2008 7:24:18 PM
|
|
glen herrmannsfeldt wrote:
> Richard Maine wrote:
> (snip)
>
>> No. My point is nothing to do with that. It is more that the loop
>> condition is one place, but the variables that control it are defined
>> elsewhere. It is that separation that makes it hard to read for me.
>> An UNTIL would be just as bad because it still isn't particularly
>> near to where the relevant variables get defined.
>
> I believe there is at least one language with a WHILE loop testing
> at the beginning, and an UNTIL loop testing at the end. It might
> be that in some cases a test at the end would reduce the separation.
C has that (but the latter is not called UNTIL). There are two uses
of the while keyword. You can have
while (condition) <statement>
or you can have
do <statement> while (condition);
Where <statement> in either case is a simple statement (terminated
by a semicolon) or is a block delimited by braces {}. In the second
form the while condition is always followed by a semicolon and
in the former case it's probably usually an error to follow the
condition immediately by a semicolon (unless you want <statement>
to be the null statement).
C does have any ways to exit the loop from places other than the
beginning or end. Their unconditional break and continue statements
have meaning corresponding to EXIT and CYCLE in Fortran, and
suffer from the same conceptual and syntactic difficulties (they cross
nesting order and usually aren't written leftmost on a line or indented
the same as the loop's delimiters).
There are, of course, languages other that C that also have similar
features. The example of C is an exitence proof of your stated
belief.
--
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
|
|
0
|
|
|
|
Reply
|
jamesgiles (2210)
|
5/17/2008 8:48:53 PM
|
|
Richard Maine wrote:
(snip)
> No. My point is nothing to do with that. It is more that the loop
> condition is one place, but the variables that control it are defined
> elsewhere. It is that separation that makes it hard to read for me. An
> UNTIL would be just as bad because it still isn't particularly near to
> where the relevant variables get defined.
I believe there is at least one language with a WHILE loop testing
at the beginning, and an UNTIL loop testing at the end. It might
be that in some cases a test at the end would reduce the separation.
-- glen
|
|
0
|
|
|
|
Reply
|
gah (12258)
|
5/17/2008 8:53:08 PM
|
|
glen herrmannsfeldt wrote:
> Richard Maine wrote:
> (snip)
>
>> No. My point is nothing to do with that. It is more that the loop
>> condition is one place, but the variables that control it are defined
>> elsewhere. It is that separation that makes it hard to read for me. An
>> UNTIL would be just as bad because it still isn't particularly near to
>> where the relevant variables get defined.
>
>
> I believe there is at least one language with a WHILE loop testing
> at the beginning, and an UNTIL loop testing at the end. It might
> be that in some cases a test at the end would reduce the separation.
>
If I remember right, I think Harris/Gould/Encore Fortran had just about
every form of these (while, until (and END DO and FOR/END FOR)) in their
Fortran 77 compiler...and weused them with abandon in our F-16
simulation code, ignoring completely any consideration of portability.
> -- glen
>
--
Gary Scott
mailto:garylscott@sbcglobal dot net
Fortran Library: http://www.fortranlib.com
Support the Original G95 Project: http://www.g95.org
-OR-
Support the GNU GFortran Project: http://gcc.gnu.org/fortran/index.html
If you want to do the impossible, don't hire an expert because he knows
it can't be done.
-- Henry Ford
|
|
0
|
|
|
|
Reply
|
garylscott (1357)
|
5/17/2008 11:20:10 PM
|
|
I never trust the compiler that sits waiting in the future.
So I assume nothing will work as expected, except my own code will I
will trust to a compiler just so far.
So when modifying the format of an exsiting file, I almost always read
the input as sequential unformatted blocks of bytes (or fixed length
direct access blocks, which seems to be the same thing apart from
processing the last (short?) record correctly) , and then processing
the bytes in the buffer for eor delimiters or final eof (or both
together).
|
|
0
|
|
|
|
Reply
|
tbwright (1098)
|
5/18/2008 12:51:51 AM
|
|
After reading everyone's valuable comments, I rewrote my routine. I
realized that the original was needlessly convoluted and had the final
line problem. The new version is much shorter, copies the final line
properly, and seems to work ok, but I am still a little worried I might
be missing something. I decided in the end to not use iostat but only
to use the branch specifiers. Any other advice is highly appreciated.
Thanks,
John
module copy_file
implicit none
private
integer, parameter :: MAX_LINE_LENGTH_ = 512
integer, parameter :: F_TMP_ = 540
public :: copy
contains
!=======================================================================
subroutine copy(oname,nname,funit)
implicit none
character (len=*), intent(in) :: oname
character (len=*), intent(in) :: nname
integer, intent(in), optional :: funit
character (len=MAX_LINE_LENGTH_) :: line
integer :: of,nf,nchars
of = F_TMP_ ; if (present(funit)) of = funit
nf = of + 1
if (adjustl(oname) .eq. adjustl(nname)) then
write(*,'(1X,A)') 'old file name and new file name are the same'
stop
end if
open(unit=of,file=oname,status='old' ,err=502)
open(unit=nf,file=nname,status='unknown',err=502)
do while (.true.)
do while (.true.)
read (of,fmt='(A)',advance='no', &
size=nchars,err=502,end=501,eor=500) line
write(nf,fmt='(A)',advance='no',err=502) line(:nchars)
end do
500 write(nf,fmt='(A)',err=502) line(:nchars)
cycle
end do
501 close(of,err=502) ; close(nf,err=502)
return
502 write(*,'(1X,A)') 'error copying FILE '//oname//' to FILE '//nname
stop
end subroutine copy
!=======================================================================
end module copy_file
|
|
0
|
|
|
|
Reply
|
gh14tq5 (118)
|
5/19/2008 10:59:56 AM
|
|
Below uses "stream" i/o which is standard with F2003
but in CVF and several other compilers using following syntax:
You are guaranteed an exact copy with identical #bytes in new file as old
file.
! -----------------
program file_copy
character :: ch
open (11,file='text.old',form='binary')
open (22,file='text.new',form='binary')
do
read (11,end=101) ch
write (22) ch
end do
101 stop
end program
|
|
0
|
|
|
|
Reply
|
dave_frank (2243)
|
5/19/2008 11:18:29 AM
|
|
David Frank wrote:
> Below uses "stream" i/o which is standard with F2003
> but in CVF and several other compilers using following syntax:
> You are guaranteed an exact copy with identical #bytes in new file as old
> file.
> ! -----------------
> program file_copy
> character :: ch
> open (11,file='text.old',form='binary')
> open (22,file='text.new',form='binary')
> do
> read (11,end=101) ch
> write (22) ch
> end do
> 101 stop
> end program
>
That's pretty nice, but until (complete) F2003 compilers become more
commonplace, I think I will stick with F95. Still, I look forward to
getting my hands on a F2003 compiler that implements the full standard.
John
|
|
0
|
|
|
|
Reply
|
gh14tq5 (118)
|
5/19/2008 11:42:41 AM
|
|
"John" <gh14tq5@yahoo.com> wrote in message news:g0rmjr$e9p$1@aioe.org...
>
> do while (.true.)
> do while (.true.)
> read (of,fmt='(A)',advance='no', &
> size=nchars,err=502,end=501,eor=500) line
> write(nf,fmt='(A)',advance='no',err=502) line(:nchars)
> end do
As a purist I would say the "while (.true.)" is superfluous and should be
removed.
There are colleagues in our office who actually like to write
if (bVal == .TRUE.) and similar
especially in the C++ form but occasionally when they venture into Fortran
code.
I think they do it just to annoy me when I have to fix some bug.
:-)
Les
|
|
0
|
|
|
|
Reply
|
l.neilson825 (106)
|
5/19/2008 1:18:24 PM
|
|
Les wrote:
> "John" <gh14tq5@yahoo.com> wrote in message
> news:g0rmjr$e9p$1@aioe.org...
....
> As a purist I would say the "while (.true.)" is superfluous and
> should be removed.
A CYCLE statement immediately followed by the corresponding
END DO is also very strange.
Why not:
do
read (of,fmt='(A)',advance='no', &
size=nchars,err=502,end=501,iostat=i) line
if (i == 0) then
write(nf,fmt='(A)',advance='no',err=502) line(:nchars)
else
write(nf,fmt='(A)',err=502) line(:nchars)
end if
end do
Given that he has both ERR= and END= specifiers, the only
remaining reason that the IOSTAT might be non-zero is end of
record. If pre-f2003 had made it easier to distinguish between
end of file and end of record you wouldn't need the END=
either.
Since he obviously regards errors as exceptional, the use of
END= remains appropriate.
Obviously he'll pick his own more mnemonic name for the
IOSTAT and add it to his list of local integer declarations.
With this substitution for his loops the code does the same
things in the same order as his.
--
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
|
|
0
|
|
|
|
Reply
|
jamesgiles (2210)
|
5/19/2008 5:09:11 PM
|
|
"John" <gh14tq5@yahoo.com> wrote in message news:g0rp3v$p7o$1@aioe.org...
> David Frank wrote:
>> Below uses "stream" i/o which is standard with F2003
>> but in CVF and several other compilers using following syntax:
>> You are guaranteed an exact copy with identical #bytes in new file as old
>> file.
>> ! -----------------
>> program file_copy
>> character :: ch
>> open (11,file='text.old',form='binary')
>> open (22,file='text.new',form='binary')
>> do
>> read (11,end=101) ch
>> write (22) ch
>> end do
>> 101 stop
>> end program
>>
>
>
> That's pretty nice, but until (complete) F2003 compilers become more
> commonplace, I think I will stick with F95. Still, I look forward to
> getting my hands on a F2003 compiler that implements the full standard.
>
> John
You probably have stream i/o syntax available as an extension in your F95.
|
|
0
|
|
|
|
Reply
|
dave_frank (2243)
|
5/19/2008 8:06:02 PM
|
|
On May 19, 6:42=A0am, John <gh14...@yahoo.com> wrote:
> David Frank wrote:
> > Below uses "stream" i/o which is standard with F2003
> > but in CVF and several other compilers using following syntax:
> > You are guaranteed an exact copy with identical #bytes in new file as ol=
d
> > file.
> > ! -----------------
> > program file_copy
> > character :: ch
> > open (11,file=3D'text.old',form=3D'binary')
> > open (22,file=3D'text.new',form=3D'binary')
> > do
> > =A0 =A0read (11,end=3D101) ch
> > =A0 =A0write (22) ch
> > end do
> > 101 stop
> > end program
>
> That's pretty nice, but until (complete) F2003 compilers become more
> commonplace, I think I will stick with F95. =A0Still, I look forward to
> getting my hands on a F2003 compiler that implements the full standard.
>
> John- Hide quoted text -
>
> - Show quoted text -
The conversion to F2003 once a compiler is available is trivial. Many
times people waste far more time trying devise a "standard conforming"
solution when a trivial extension such as this will suffice for the
particular problem at hand.
|
|
0
|
|
|
|
Reply
|
garylscott (1357)
|
5/20/2008 3:31:42 AM
|
|
Les wrote:
> "John" <gh14tq5@yahoo.com> wrote in message news:g0rmjr$e9p$1@aioe.org...
>> do while (.true.)
>> do while (.true.)
>> read (of,fmt='(A)',advance='no', &
>> size=nchars,err=502,end=501,eor=500) line
>> write(nf,fmt='(A)',advance='no',err=502) line(:nchars)
>> end do
>
> As a purist I would say the "while (.true.)" is superfluous and should be
> removed.
> There are colleagues in our office who actually like to write
> if (bVal == .TRUE.) and similar
> especially in the C++ form but occasionally when they venture into Fortran
> code.
> I think they do it just to annoy me when I have to fix some bug.
> :-)
>
> Les
>
>
I don't mind using while(.true.). I think it is very clear in this case
(at least to me).
I missed that cycle statement. I think I originally had some lines
below it, deleted them, but missed the cycle statement.
John
|
|
0
|
|
|
|
Reply
|
gh14tq5 (118)
|
5/20/2008 11:07:48 AM
|
|
GaryScott wrote:
> On May 19, 6:42 am, John <gh14...@yahoo.com> wrote:
>> David Frank wrote:
>>> Below uses "stream" i/o which is standard with F2003
>>> but in CVF and several other compilers using following syntax:
>>> You are guaranteed an exact copy with identical #bytes in new file as old
>>> file.
>>> ! -----------------
>>> program file_copy
>>> character :: ch
>>> open (11,file='text.old',form='binary')
>>> open (22,file='text.new',form='binary')
>>> do
>>> read (11,end=101) ch
>>> write (22) ch
>>> end do
>>> 101 stop
>>> end program
>> That's pretty nice, but until (complete) F2003 compilers become more
>> commonplace, I think I will stick with F95. Still, I look forward to
>> getting my hands on a F2003 compiler that implements the full standard.
>>
>> John- Hide quoted text -
>>
>> - Show quoted text -
>
> The conversion to F2003 once a compiler is available is trivial. Many
> times people waste far more time trying devise a "standard conforming"
> solution when a trivial extension such as this will suffice for the
> particular problem at hand.
Yes, but where I work, there are various Fortran compilers and the code
needs to work on all of them. Of the ones we have, I think only g95 and
gfortran have any F2003 extensions at all. We usually only use these
for development because the executables are slower than our other compilers.
John
|
|
0
|
|
|
|
Reply
|
gh14tq5 (118)
|
5/20/2008 11:10:39 AM
|
|
"John" <gh14tq5@yahoo.com> wrote in message news:g0ubji$hcs$2@aioe.org...
> GaryScott wrote:
>> The conversion to F2003 once a compiler is available is trivial. Many
>> times people waste far more time trying devise a "standard conforming"
>> solution when a trivial extension such as this will suffice for the
>> particular problem at hand.
> Yes, but where I work, there are various Fortran compilers and the code
> needs to work on all of them. Of the ones we have, I think only g95 and
> gfortran have any F2003 extensions at all. We usually only use these for
> development because the executables are slower than our other compilers.
It might be possible to get by with code that detects the compiler
and then uses the appropriate syntax for the compiler to get stream
I/O. At one time I had this strategy working on several compilers:
http://home.comcast.net/~kmbtib/Fortran_stuff/fire2.f90 but as the
different vendors fix bugs (and don't implement f03 stream I/O) the
code might have to get changed to work again.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
|
|
0
|
|
|
|
Reply
|
not_valid (1681)
|
5/20/2008 12:35:09 PM
|
|
James Van Buskirk wrote:
> "John" <gh14tq5@yahoo.com> wrote in message news:g0ubji$hcs$2@aioe.org...
>
>> GaryScott wrote:
>
>>> The conversion to F2003 once a compiler is available is trivial. Many
>>> times people waste far more time trying devise a "standard conforming"
>>> solution when a trivial extension such as this will suffice for the
>>> particular problem at hand.
>
>> Yes, but where I work, there are various Fortran compilers and the code
>> needs to work on all of them. Of the ones we have, I think only g95 and
>> gfortran have any F2003 extensions at all. We usually only use these for
>> development because the executables are slower than our other compilers.
>
> It might be possible to get by with code that detects the compiler
> and then uses the appropriate syntax for the compiler to get stream
> I/O. At one time I had this strategy working on several compilers:
> http://home.comcast.net/~kmbtib/Fortran_stuff/fire2.f90 but as the
> different vendors fix bugs (and don't implement f03 stream I/O) the
> code might have to get changed to work again.
>
Well, I really need the code to work on whatever compiler someone may
throw at it, so it has to be portable. Also, the people I work for
don't want me to get too fancy with my Fortran. They even get
uncomfortable with F95. Sometimes if I give them a simple program, the
first thing they do is try to rewrite it in F77 so they can "understand
it". It drives me a little crazy. For now I will stick with the
portable yet slightly more complicated routine.
Your technique is pretty interesting though. However, I do not quite
understand how the compilers are being detected. Are you relying on
some subtle individual behaviors of each compiler? If so, did you just
stumble on the behaviors by accident? For example, why does the NEQV of
in is_ftn95 pass for a ft95 compiler and not G95?
John
|
|
0
|
|
|
|
Reply
|
gh14tq5 (118)
|
5/20/2008 9:32:47 PM
|
|
"John" <gh14tq5@yahoo.com> wrote in message news:g0vg1u$8mm$1@aioe.org...
> Your technique is pretty interesting though. However, I do not quite
> understand how the compilers are being detected. Are you relying on some
> subtle individual behaviors of each compiler? If so, did you just stumble
> on the behaviors by accident? For example, why does the NEQV of in
> is_ftn95 pass for a ft95 compiler and not G95?
The NEQV stuff was a bug of a version of ftn95 where overloading
operator(.EQV.) and operator(.NEQV.) didn't work properly. I ran
across that when trying to exploit the anomalous precedence of
operator(.XOR.) in DVF/CVF/ifort. In the latter
a .XOR. b .NEQV. c
associated as
(a .XOR. b) .NEQV. c
The ftn95 bug caused a fault here but as shown could be used to
detect ftn95 itself. One could try to detect DVF and successors
via checking associativity of
a .MyNewOperator. b .XOR. c
but there is a problem with LF95 that keeps it from compiling
anything with operator(.XOR.) which is a shame because this is
pretty much the perfect Easter egg in that it's a benign
deviation from standard behavior which ifort will never change
and nobody in their right mind would ever copy!
The is_g95 function I later found to be a bug not only g95 had
fixed but also most other compilers. For some reason ifort
never fixed it, and this one is not so benign, causing just
about any OO-style code to fail on ifort. LF95 discontinued
Windows support before they fixed it. This function therefore
is really checking for lf95 or dvf/cvf/ifort rather than
discovering whether it's g95 or not.
Another way to detect compilers is to examine the low-level behavior
of LOGICAL operators. Vendors do completely lame things in this
area like violate the truth tables. They are quite stubborn about
bugs in this area, instead considering them features so they can be
used in the longer term to detect compilers. I had a version that
detected a compiler or two in this fashion (pathscale was really
anomalous IIRC) but it seems I have not posted it.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
|
|
0
|
|
|
|
Reply
|
not_valid (1681)
|
5/21/2008 4:52:59 PM
|
|
I value the EXIT statement, but I didn't realise until it was pointed
out by J. Giles how it affects readability.
So I want to float an idea. How about an
EXIT <label> IF (condition)
statement extension?
The condition now appears at the end of the statement, keeping EXIT at
the right nesting level, that of the body
of the loop.
One drawback is that it looks like an action to be performed ('EXIT'),
until your eyes reach the condition.
So maybe:
EXITIF <LABEL> <CONDITION>
Given that EXITing mid-loop requires a test, I expect to hear that
this syntax has been considered and rejected in the past.
Now it's just an idea I'm floating, so if you can sink it, fire
away!
(When I write EXIT-less loops, I keep a logical flag like
ALL_OK_SO_FAR :-) and only execute lines if that is .true.. Lots of
if tests then, and lots of no-op loop cycles. I am still working out
which style I prefer. )
Oh, one last thing occurred to me. It is possible to line up EXIT
with the loop body , or the loop control statements, by using the line
continuation characters, but this has a readability problem too, I
think. Here's how things look:
!----! EXIT is two nesting levels in. !----!
DO WHILE( SOMETHING )
...
...
IF ( SOMETHING_ELSE )EXIT
...
...
END DO
!----! Faking exit at the nesting level of the loop control
statements. !----!
! Readability problem, have to look at the preceding line.
! Maintainability problem, two lines have to stay together, hence
use of two ampersands.
DO WHILE( SOMETHING )
...
...
IF ( SOMETHING_ELSE ) &
& EXIT
...
...
END DO
!----! Suggested EXITIF !----!
DO WHILE( SOMETHING )
...
...
EXITIF ( SOMETHING_ELSE )
...
...
END DO
|
|
0
|
|
|
|
Reply
|
andrej.panjkov (14)
|
5/22/2008 5:48:40 AM
|
|
andrej.panjkov@climatechange.qld.gov.au wrote:
> I value the EXIT statement, but I didn't realise until it was pointed
> out by J. Giles how it affects readability.
>
> So I want to float an idea. How about an
> EXIT <label> IF (condition)
> statement extension?
What is wrong with spelling it as UNTIL?
--
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
|
|
0
|
|
|
|
Reply
|
jamesgiles (2210)
|
5/22/2008 6:08:56 AM
|
|
> > So I want to float an idea. How about an
> > EXIT <label> IF (condition)
> > statement extension?
>
> What is wrong with spelling it as UNTIL?
>
> --
Let's see:
DO WHILE( SOMETHING )
...
...
UNTIL LABEL ( SOMETHING_ELSE )
...
...
END DO
DO WHILE( SOMETHING )
...
...
EXITIF LABEL ( SOMETHING_ELSE )
...
...
END DO
Sure, why not. Any discussion here would be about personal taste I
think. I used to find WHILE and UNTIL a little awkward
because they mean something different to 'while' and 'until', the
English words. But one gets over that. I think having the exit
condition at the end of the line is the improvement.
|
|
0
|
|
|
|
Reply
|
andrej.panjkov (14)
|
5/22/2008 7:07:48 AM
|
|
andrej.panjkov@climatechange.qld.gov.au wrote:
....
> DO WHILE( SOMETHING )
> ...
> ...
> UNTIL LABEL ( SOMETHING_ELSE )
> ...
> ...
> END DO
>
> DO WHILE( SOMETHING )
> ...
> ...
> EXITIF LABEL ( SOMETHING_ELSE )
> ...
> ...
> END DO
If the DO statement mentions no label, then none is needed on the
UNTIL (or even the EXITIF). In fact, there can't be one.
--
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
|
|
0
|
|
|
|
Reply
|
jamesgiles (2210)
|
5/22/2008 7:20:27 AM
|
|
andrej.panjkov@climatechange.qld.gov.au wrote:
>>> So I want to float an idea. How about an
>>> EXIT <label> IF (condition)
>>> statement extension?
>> What is wrong with spelling it as UNTIL?
>>
>> --
>
> Let's see:
>
> DO WHILE( SOMETHING )
> ...
> ...
> UNTIL LABEL ( SOMETHING_ELSE )
> ...
> ...
> END DO
>
> DO WHILE( SOMETHING )
> ...
> ...
> EXITIF LABEL ( SOMETHING_ELSE )
> ...
> ...
> END DO
>
> Sure, why not. Any discussion here would be about personal taste I
> think. I used to find WHILE and UNTIL a little awkward
> because they mean something different to 'while' and 'until', the
> English words. But one gets over that. I think having the exit
> condition at the end of the line is the improvement.
My news feed has been patchy of late, and I've missed some posts so forgive me if this is
a rehash:
1) Assuming "LABEL" is a construct name, what's the problem with the current syntax:
IF ( something_else ) EXIT label
?
2) Assuming "LABEL" is NOT a construct name, what's the problem with this current syntax:
IF ( something_else ) GOTO label
?
It's a personal opinion, but it seems to me that the current EXIT syntax coupled with a
simple DO statement takes into account both the WHILE and UNTIL forms (borrowing syntax
from IDL):
WHILE (something) DO BEGIN
....
ENDWHILE
and
REPEAT BEGIN
....
ENDREP UNTIL (something)
It seems to me that doing (back to Fortran :o) :
DO
....
IF (something) EXIT
....
END DO
accomodates both forms with judicious placement of the "IF" statement. Is readability that
severely impacted in the last form?
cheers,
paulv
|
|
0
|
|
|
|
Reply
|
paul.vandelst (1947)
|
5/22/2008 1:22:55 PM
|
|
On May 22, 8:22=A0am, Paul van Delst <Paul.vanDe...@noaa.gov> wrote:
> andrej.panj...@climatechange.qld.gov.au wrote:
> >>> So I want to float an idea. =A0How about an
> >>> EXIT <label> IF (condition)
> >>> statement extension?
> >> What is wrong with spelling it as UNTIL?
>
> >> --
>
> > Let's see:
>
> > =A0 DO WHILE( SOMETHING )
> > =A0 =A0 =A0...
> > =A0 =A0 =A0...
> > =A0 UNTIL LABEL ( SOMETHING_ELSE )
> > =A0 =A0 =A0...
> > =A0 =A0 =A0...
> > =A0 END DO
>
> > =A0 DO WHILE( SOMETHING )
> > =A0 =A0 =A0...
> > =A0 =A0 =A0...
> > =A0 EXITIF LABEL ( SOMETHING_ELSE )
> > =A0 =A0 =A0...
> > =A0 =A0 =A0...
> > =A0 END DO
>
> > Sure, why not. =A0Any discussion here would be about personal taste I
> > think. =A0I used to find WHILE and UNTIL a little awkward
> > because they mean something different to 'while' and 'until', the
> > English words. =A0But one gets over that. =A0I think having the exit
> > condition at the end of the line is the improvement.
>
> My news feed has been patchy of late, and I've missed some posts so forgiv=
e me if this is
> a rehash:
>
> 1) Assuming "LABEL" is a construct name, what's the problem with the curre=
nt syntax:
> =A0 =A0 =A0 IF ( something_else ) EXIT label
> ?
>
> 2) Assuming "LABEL" is NOT a construct name, what's the problem with this =
current syntax:
> =A0 =A0 =A0 IF ( something_else ) GOTO label
> ?
>
> It's a personal opinion, but it seems to me that the current EXIT syntax c=
oupled with a
> simple DO statement takes into account both the WHILE and UNTIL forms (bor=
rowing syntax
> from IDL):
>
> =A0 =A0WHILE (something) DO BEGIN
> =A0 =A0 =A0....
> =A0 =A0ENDWHILE
>
> and
>
> =A0 =A0REPEAT BEGIN
> =A0 =A0 =A0....
> =A0 =A0ENDREP UNTIL (something)
>
> It seems to me that doing (back to Fortran :o) :
>
> =A0 =A0DO
> =A0 =A0 =A0....
> =A0 =A0 =A0IF (something) EXIT
> =A0 =A0 =A0....
> =A0 =A0END DO
>
> accomodates both forms with judicious placement of the "IF" statement. Is =
readability that
> severely impacted in the last form?
Absolutely not. Readability is just fine. I prefer indention of the
exit statement from the loop anyway. It seems visually non-symetrical
the other way to me.
>
> cheers,
>
> paulv- Hide quoted text -
>
> - Show quoted text -
|
|
0
|
|
|
|
Reply
|
garylscott (1357)
|
5/22/2008 1:57:18 PM
|
|
Paul van Delst wrote:
....
> It's a personal opinion, but it seems to me that the current EXIT
> syntax coupled with a simple DO statement takes into account both the
> WHILE and UNTIL forms (borrowing syntax from IDL):
>
> WHILE (something) DO BEGIN
> ....
> ENDWHILE
>
> and
>
> REPEAT BEGIN
> ....
> ENDREP UNTIL (something)
>
> It seems to me that doing (back to Fortran :o) :
>
> DO
> ....
> IF (something) EXIT
> ....
> END DO
>
> accomodates both forms with judicious placement of the "IF"
> statement. Is readability that severely impacted in the last form?
Yes.
People fail to see the EXIT (especially if the loop also has a
normal control or another EXIT that they already *have* found).
This isn't a theory. I've seen people make the mistake. In fact,
I have found that it's not particularly uncommon (when dealing
with users complaining of errors they can't find).
All other control constructs are designed with the intent that
users put the related control statements on the left. ELSEIFs
and ELSEs are buried to the right within IF-ENDIF blocks.
CASEs aren't hidden in the clutter between SELECT
and END SELECT statements - they are on the left-hand
end of the line they appear on. EXITS are quite hard to
place on the left.
The second problem, which causes the first, is that prematurely
leaving a loop is *invariably* a conditional act. Yet EXIT is
an unconditional statement. So it always has to be nested within
another control construct. The constructs within which it is
nested are those which often appear nested within loops - and
seldom contain EXITs. So, it's easy to overlook an EXIT
there.
Now, I'm not a cognitive psychologist, but I have read quite
a bit about ergonomics. (I think doing so should be a prerequisite
for language design.) The above two paragraphs each represent
fairly well established principles. You really should try to make
similar things work consistently, yet EXIT is anomalous compared
to other control statements. And you really shouldn't bury something
inside usually unrelated other stuff. This is informally stated, but
I don't think some formal psychological terminology would make
them more understandable (even if I could remember such, I like
it when things are explained simply myself).
By the way, if you wish to hide things the rules are just the opposite:
you *should* be inconsistent and and you *should* place things with
apparently unrelated stuff. So maybe EXIT was designed to be easy
to hide.
--
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
|
|
0
|
|
|
|
Reply
|
jamesgiles (2210)
|
5/22/2008 6:11:54 PM
|
|
On May 22, 1:11=A0pm, "James Giles" <jamesgi...@worldnet.att.net> wrote:
> Paul van Delst wrote:
>
> ...
>
>
>
>
>
> > It's a personal opinion, but it seems to me that the current EXIT
> > syntax coupled with a simple DO statement takes into account both the
> > WHILE and UNTIL forms (borrowing syntax from IDL):
>
> > =A0 WHILE (something) DO BEGIN
> > =A0 =A0 ....
> > =A0 ENDWHILE
>
> > and
>
> > =A0 REPEAT BEGIN
> > =A0 =A0 ....
> > =A0 ENDREP UNTIL (something)
>
> > It seems to me that doing (back to Fortran :o) :
>
> > =A0 DO
> > =A0 =A0 ....
> > =A0 =A0 IF (something) EXIT
> > =A0 =A0 ....
> > =A0 END DO
>
> > accomodates both forms with judicious placement of the "IF"
> > statement. Is readability that severely impacted in the last form?
>
> Yes.
>
> People fail to see the EXIT (especially if the loop also has a
> normal control or another EXIT that they already *have* found).
> This isn't a theory. =A0I've seen people make the mistake. =A0In fact,
> I have found that it's not particularly uncommon (when dealing
> with users complaining of errors they can't find).
I won't argue that there may be some tinee tiney benefit to having a
differently structured EXIT, but to me, whether or not to leave a loop
is just another conditional being tested within a loop which follows
naturally an IF statement as designed. Most of my looping constructs
are conditional branching controls, with little other types of
computation (i.e. display some GUI object, hide it, delete it, refresh
it).
<snip>
> - Show quoted text -
|
|
0
|
|
|
|
Reply
|
garylscott (1357)
|
5/22/2008 6:19:17 PM
|
|
GaryScott wrote:
> On May 22, 1:11 pm, "James Giles" <jamesgi...@worldnet.att.net> wrote:
....
>> People fail to see the EXIT (especially if the loop also has a
>> normal control or another EXIT that they already *have* found).
>> This isn't a theory. I've seen people make the mistake. In fact,
>> I have found that it's not particularly uncommon (when dealing
>> with users complaining of errors they can't find).
>
> I won't argue that there may be some tinee tiney benefit to having a
> differently structured EXIT, [...]
Thank you for your well thought out response. I especially like
the "tinee tiney" part. Shows how thoroughly you understand the
meaning of the phrase "it's not particularly uncommon". Given
the number of actually hard to provide features that you've
belligerently promoted over the years, and the fact that I can't
remember any with more than a "VERY tinee tiney" benefit
to them, you perhaps shouldn't be throwing stones. At least not
ones criticizing something for minimal benefits.
--
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
|
|
0
|
|
|
|
Reply
|
jamesgiles (2210)
|
5/22/2008 6:39:43 PM
|
|
On May 22, 1:39=A0pm, "James Giles" <jamesgi...@worldnet.att.net> wrote:
> GaryScott wrote:
> > On May 22, 1:11 pm, "James Giles" <jamesgi...@worldnet.att.net> wrote:
> ...
> >> People fail to see the EXIT (especially if the loop also has a
> >> normal control or another EXIT that they already *have* found).
> >> This isn't a theory. I've seen people make the mistake. In fact,
> >> I have found that it's not particularly uncommon (when dealing
> >> with users complaining of errors they can't find).
>
> > I won't argue that there may be some tinee tiney benefit to having a
> > differently structured EXIT, [...]
>
> Thank you for your well thought out response. =A0I especially like
> the "tinee tiney" part. =A0Shows how thoroughly you understand the
> meaning of the phrase "it's not particularly uncommon". =A0Given
> the number of actually hard to provide features that you've
> belligerently promoted over the years, and the fact that I can't
> remember any with more than a "VERY tinee tiney" benefit
> to them, you perhaps shouldn't be throwing stones. =A0At least not
> ones criticizing something for minimal benefits.
Sorry I wasn't intending to throw stones. I don't object to adding
such a feature, but that is my assessment of this particular item in
terms of the overall value in changing the existing design or adding
an additional feature. I don't find the existing design particularly
aggregious.
Most of my own suggested features have related to a desire for more
"system programming" features. Since a very high percentage of
applications written globally (not necessarily those written in
Fortran) require features such as multiprocessing, threads,
synchronization facilities, etc., I personnally assess those as quite
high on my priority list and that of most programmers I know (a lot of
embedded software developers, I admit). I agree that more time has
been spent arguing about particular implementation suggestions than
necessary. It has never been my intent to design any particular
feature. I don't have the expertise or interest. My descriptions are
merely an attempt to describe the capability I desire in hopes that
someone with more time and understanding will take it on. That has
actually happened a few times. I very much value your opinions and
typically read them first (and usually agree with them), but I feel
that you sometimes overstate the magnitude of the impact or value
regarding efficiency, legibility, error-proneness, etc.
>
> --
> 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." =A0 -- =A0C. A. R. Hoare
|
|
0
|
|
|
|
Reply
|
garylscott (1357)
|
5/22/2008 9:29:28 PM
|
|
GaryScott wrote:
....
> [...] but I feel
> that you sometimes overstate the magnitude of the impact or value
> regarding efficiency, legibility, error-proneness, etc.
Then your job has never involved dealing with users and their
coding errors. I don't actually "fly off the handle" on issues that
I haven't seen ample evidence that they really are as important
as I describe.
--
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
|
|
0
|
|
|
|
Reply
|
jamesgiles (2210)
|
5/22/2008 9:58:32 PM
|
|
James Giles wrote:
> glen herrmannsfeldt wrote:
>>Richard Maine wrote:
>>(snip)
>>>No. My point is nothing to do with that. It is more that the loop
>>>condition is one place, but the variables that control it are defined
>>>elsewhere. It is that separation that makes it hard to read for me.
>>>An UNTIL would be just as bad because it still isn't particularly
>>>near to where the relevant variables get defined.
The convenience of the C for statement is that it keeps
all loop control operations together. That is,
for(a;b;c) { d }
is equivalent to
a;
while(b) {
d;
c;
}
That is, c, which usually changes the loop index variable,
is actually done at the end of the loop. (a, b, and c are
any expression possibly unrelated to loop initialization,
testing, and loop variable modification.)
>>I believe there is at least one language with a WHILE loop testing
>>at the beginning, and an UNTIL loop testing at the end. It might
>>be that in some cases a test at the end would reduce the separation.
> C has that (but the latter is not called UNTIL). There are two uses
> of the while keyword. You can have
> while (condition) <statement>
> or you can have
> do <statement> while (condition);
> Where <statement> in either case is a simple statement (terminated
> by a semicolon) or is a block delimited by braces {}. In the second
> form the while condition is always followed by a semicolon and
> in the former case it's probably usually an error to follow the
> condition immediately by a semicolon (unless you want <statement>
> to be the null statement).
Interesting way to describe it. There is also the
difference between using semicolon as a statement
terminator (C, C++, Java, PL/I) or a separator (Pascal).
Anyway, it is PL/I that has WHILE and UNTIL, where WHILE
describes a test at the beginning, and UNTIL a test at the end
(even though the expression is at the top of the loop).
The C form:
do <statement> while (condition);
in PL/I would look like
do until(�(condition)); /* note the not sign */
statement;
end;
It seems slightly convenient in that loops with a test
at the end might tend to test for a negative condition
more often than ones that test at the beginning.
PL/I uses the DO statement both for looping and for grouping.
if condition then do;
statements;
end;
-- glen
|
|
0
|
|
|
|
Reply
|
gah (12258)
|
5/22/2008 10:09:48 PM
|
|
On May 22, 5:20 pm, "James Giles" <jamesgi...@worldnet.att.net> wrote:
> andrej.panj...@climatechange.qld.gov.au wrote:
>
> ...
>
> > DO WHILE( SOMETHING )
> > ...
> > ...
> > UNTIL LABEL ( SOMETHING_ELSE )
> > ...
> > ...
> > END DO
>
> > DO WHILE( SOMETHING )
> > ...
> > ...
> > EXITIF LABEL ( SOMETHING_ELSE )
> > ...
> > ...
> > END DO
>
> If the DO statement mentions no label, then none is needed on the
> UNTIL (or even the EXITIF). In fact, there can't be one.
>
Yeah, I guess I was thinking about nested loops, where the EXIT LABEL
might be a label on an outer loop.
LOOP1: &
DO WHILE (SOMETHING)
...
DO WHILE (SOMETHING)
...
UNTIL LOOP1: (SOMETHING)
...
END DO
...
END DO LOOP1
|
|
0
|
|
|
|
Reply
|
andrej.panjkov (14)
|
5/23/2008 12:10:34 AM
|
|
On May 22, 4:58=A0pm, "James Giles" <jamesgi...@worldnet.att.net> wrote:
> GaryScott wrote:
>
> ...
>
> > [...] =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0but I feel
> > that you sometimes overstate the magnitude of the impact or value
> > regarding efficiency, legibility, error-proneness, etc.
>
> Then your job has never involved dealing with users and their
> coding errors. =A0
Actually, it has somewhat. I am intimately familiar with millions
(seems like billions) of lines of avionics models and data processing
code, written in extended F77. I maintained, modified, assisted
debugging efforts, etc. I don't recall ever seeing an anomaly in this
code relating to use of the similar EXIT extension that was
supported. Doesn't mean there were none of course. Most of the
coding errors were similar to not checking peripheral device status
words or not waiting sufficient time before checking and declaring a
device failure prematurely. Or applying an incorrect scaling or
mapping factor in the consolidated scaling process (had to be scaled
and mapped to the appropriate serial bus interface).
The coding standard was pretty strict and reasonably well followed and
code had to be processed for approval through CM and Fagan review
processes.
My regular job though is unrelated to programming and my degree is EE,
not CS. The job included risk and failure analysis of code and
systems for things like single point failures, backup operation,
degraded operation. Not entirely non-applicable, but not closely
related. That's why I defer all things Fortran to the experts. I
only know what I'd like to be able to accomplish. I certainly have
opinions as to how I'd like things implemented, but I'm perfectly
happy for those more knowledgeable to work out the details or propose
"better" solutions.
> I don't actually "fly off the handle" on issues that
> I haven't seen ample evidence that they really are as important
> as I describe.
>
> --
> 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." =A0 -- =A0C. A. R. Hoare
|
|
0
|
|
|
|
Reply
|
garylscott (1357)
|
5/23/2008 2:24:07 PM
|
|
|
38 Replies
58 Views
(page loaded in 1.945 seconds)
|