3

I'm studying Fortran from the book of Stephen Chapman "Fortran for Scientists and Engineers" (2018).

In page 134, the author wrote this:

Good Programming Practice:

Do not use DO WHILE loops in new programs. Use the more general while loop instead.

This sentence is puzzling me a lot. Is DO-WHILE an unwanted practice? I often find DO-WHILE neater to work with. Is there any disadvantage of using DO-WHILE in terms of speed?

DO-WHILE

INTEGER :: i = -1

DO WHILE (i < 0)
    PRINT *, 'Enter a non-negative number:'
    READ(*,*) i
END DO

General while loop:

INTEGER :: i = -1

DO
    PRINT *, 'Enter a non-negative number:'
    READ(*,*) i
    IF (i >= 0) EXIT
END DO
jps
  • 20,041
  • 15
  • 75
  • 79
baki
  • 41
  • 3
  • 1
    Interesting. Never heard of this advice. Do-while looks a little more 'structured', forcing the author to state the terminal condition in a standard place. So you could make the argument that "general" while is more versatile. Maybe there's a one or two assembly instruction advantage the general block? My fortran is rusty (like 1970s rusty!) so I'll be curious to see what smart people have to say about this. – danh Jun 14 '22 at 23:50
  • 2
    This looks like a style guide. Style is always subjective to a degree. `Do While` in certain quarters has a reputation of being inefficient, which it can be when compared to a `Do i = ...` loop doing the same thing, but I can't see why in terms of speed it will be any more or less efficient than a "general" loop. And sometimes IMO it is just the right tool for the job, and a bit more readable than a equivalent "general" do. Personally I would ignore the above. – Ian Bush Jun 15 '22 at 04:21
  • 2
    This is just a matter of personal style and it is pretty subjective. There is no hard objective reason. I normally teach my students the same, it is also shown the same in the Fortran Explaines series, but it is really subjective. Someone else will recommend to use `do while`. – Vladimir F Героям слава Jun 15 '22 at 05:04
  • 1
    DO WHILE (some logical) makes sense, and I use it regularly. Otherwise I usually use DO=1, SIZE(). In your example you could just omit the loop if you make I=ABS(I)… except for I=0. So it sort of makes sense to use the DO WHILE here (IME). – Holmz Jun 15 '22 at 07:47

2 Answers2

2

I can read from this book, just before the citation you give :

This construct is a special case of the more general while loop, in which the exit test must always occur at the top of the loop. There is no reason to ever use it, since the general while loop does the same job with more flexibility.

These are mostly facts, except "There is no reason to ever use it", which is just the personal opinion of the author. And anyway "there is no reason to use it" is not the same as "there are reasons to never use it" (as far as I know there are no such reasons).

That said, as a matter of style, in the particular example you give, the do while construct is not the best choice IMO, as it forces you to (artificially) initialize i before the loop. The initialization is not needed with the general do loop.

EDIT : as mentioned in the comments the initialization is actually still needed. But this is because of the READ(*,*) that does not garantee i to be assigned. Such a read should be protected against possible input errors, but this a different topic...

PierU
  • 1,391
  • 3
  • 15
  • While I don't argue favouring avoiding the `do while` of the question, I do disagree strongly that it forces an "artificial" setting of `i` before the read statement. `integer i; read *, i; print *, i; end` is, I'm afraid, just broken Fortran code, because this leaves open the possibility of illegally referencing an undefined variable. `i` in this case should be defined before that read, like `integer :: i=-1; read *, i; print *, i; end`. – francescalus Jun 15 '22 at 15:50
  • @francescalus I'm not sure about what the standard says for unformatted `READ`, but I indeed assume here that `i` is always assigned one way or another upon return from the `READ`. Maybe I'm wrong... Anyway, the right way would be to read a string, test if the string contains only digits (with possibly leading/trailing spaces), and if yes reading `i` from the string. – PierU Jun 15 '22 at 16:59
  • No, list-directed input makes no guarantees that the effective item (`i` in this case) is defined by the read. Equally, you can't read in to a temporary string and analyse that string without defining it beforehand, because the read may leave that test string undefined. If you need to reference a variable which could be affected by a list-directed read, the only safe way to do that involves defining it before the read is attempted. – francescalus Jun 15 '22 at 17:05
  • (See [this question](https://stackoverflow.com/q/60189406/3157076) for a slightly different take on this.) – francescalus Jun 15 '22 at 17:10
  • @francescalus OK, but I was rather thinking about an explicit string format `READ(*,'(A)') string`: in this case `string` is garanteed to be assigned, right ? – PierU Jun 16 '22 at 07:02
2

Is there any disadvantage of using DO-WHILE in terms of speed?

No. There is no general reason why do while would be slower than do. A decent optimising compiler should always be able to convert a do while loop into the equivalent do loop (although not always vice-versa). Of course, if you are interested in performance in a specific case then you should try both and profile the code rather than relying on generalities.

Is DO-WHILE an unwanted practice?

No. If a do while loop is the clearest way of expressing your code, use a do while loop.

The argument "X is more general than Y, so always use X instead of Y" is clearly a fallacious over-generalisation. A GOTO is more general than a do loop, but you certainly shouldn't be replacing your do loops with GOTOs.

veryreverie
  • 2,871
  • 2
  • 13
  • 26