file copy routine

  • Follow


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)


Reply: