Why dijkstra suggested premature loop exit prohibition
Some additional notes Here are some interesting peripheral points that I left out of my main discussion because I wanted to stick to the main point, which was: "Dijkstra was not insane". I said in an earlier post that "I often find Dijkstra's innumerable screeds very tiresome in their unkind, unforgiving, and unrealistic attitudes toward programmers.
You may not like him, and you may not agree with him, but you'll be better off listening to him. An archive of Dijkstra's miscellaneous notes and essays a pre-blogging blog, if you like is maintained at the University of Texas.
I recommend it. Then you can conclude the same thing about the entire if-else block. Actually, your job is slightly easier. Let's write this: [ x ] E [ y ] to mean that code E , given precondition x , produces postcondition y. That is, if we know that x is true when E begins execution, then we know that y is true when E finishes.
We can make the same conclusion from weaker assumptions. Why do we use if-else blocks anyway? This is the reason: we want to be able to write code to guarantee something like this: [ x ] BLAH [ y ] but we only know how to guarantee [ x and q ] FOO [ y ] and [ x and not q ] BAR [ y ] for some q. So we write two blocks of code, each of which accomplishes y under some circumstances, and use if-else to make sure that the right one is selected under the right circumstances.
Similar to break but worse , in the presence of goto you are on very shaky ground in trying to conclude anything about whether the program is correct. Suppose you know that C is correct if its precondition an array of URLs is satisfied.
And you know that B will set up that precondition that is, the array if its precondition is satisfied, so it seems like you are all right. But no, because block W somewhere else might have goto C; and transfer control to C without setting up the precondition, and then C could cause winged demons to fly out of your nose.
Further reading For a quick overview, see the Wikipedia article on Hoare logic. Hoare logic is the [ x ] E [ y ] notation I used above, and a set of rules saying how to reason with claims of that form.
For example, one rule of Hoare logic defines the meaning of the null statement: if ; is the null statement, then [ p ] ; [ p ] for all conditions p. Hoare logic was invented by Tony Hoare, who also invented the Quicksort algorithm. Dijkstra introduces a function called wp for "weakest precondition". Given a piece of code C and a desired postcondition q , wp C , q is the weakest precondition that is sufficient for code C to accomplish q. This might confuse the reader into thinking the return causes the function the lambda is in to return, and not the lambda itself.
Xunie: If your loop is so complicated, that you forget that you are in a lambda, it is time to put them in a different function, but for simple cases, this should work quite well.
I think this solution is beautiful — tuket. You can capture the lambda in a RIIA template that gives it a name and calls it in dtor aka scope gaurd. This would not add any performance gain but can improve readabilty and reduce the risk of missing the function call parenthesis. I tested this on godbolt and it appears to compile to identical code to using a goto!
Another advantage of this solution over goto is that labels only work if they label a statement. Show 1 more comment. Greg Hewgill Greg Hewgill k gold badges silver badges bronze badges. That's a C problem. With RIAA early return is not a problem as all the problems associated with early return are correctly handled. What is RIAA? Is that anything like RAII? Depends how many for loops he's got and how deep the nest goes You can use goto to break out of any number of loops.
Mitja 1, 29 29 silver badges 31 31 bronze badges. Karl Voigtland Karl Voigtland 7, 31 31 silver badges 29 29 bronze badges. A good answer in that it explains that "goto is harmful" meme is strongly tied to the more generalized "control flow interruption is harmful" statement. It is meaningless to say "goto is harmful", and then turn around and recommend using break or return.
Pavel: break and return have the advantage over goto that you don't need to hunt for a label in order to find where they go. Yes, underneath they are some kind of goto , but a very restricted one. They are a lot easier to decipher by a programmer's pattern-matching brain than the unrestricted goto.
So IMO they are preferable. It is just better tolerated than a goto. KarlVoigtland the Dijkstra link is outdated; this appears to be working: blog. There is absolutely nothing wrong with using goto in this situation. A well placed goto is leaps and bounds better and more readable than many of the contorted solutions otherwise proposed. How about this? In this case, using the real goto makes core more readable and better-performing.
A code example using goto and a label to break out of a nested loop: for ;; for ;; goto theEnd; theEnd:. Helio Santos Helio Santos 6, 3 3 gold badges 23 23 silver badges 30 30 bronze badges. Deqing Deqing Sorry to tell, but lambdas are not so lightweight at least in MSVC This only overcomplicates the already complex code : Sometimes, goto is the only solution.
Or if you write complex automata with "goto state X" documentation, then goto is actually making the code read as written in the document. Also, C and go both have goto with a purpose: no language is turing-complete without a goto, and gotos are often the best used tools for writing intermediate translator or assembly-like code.
Azeemali Hashmani Azeemali Hashmani 1 1 silver badge 5 5 bronze badges. Rob Rob 2, 13 13 silver badges 17 17 bronze badges. JuliusAlphonso JuliusAlphonso 33 8 8 bronze badges. I'm assuming that the iterator for the first loop is i. Vikas Bansal Vikas Bansal 10 10 silver badges 16 16 bronze badges.
Patrick Glandien Patrick Glandien 7, 5 5 gold badges 38 38 silver badges 47 47 bronze badges. I know this is old post. But I would suggest a bit logical and simpler answer.
Aditya Jagtap Aditya Jagtap 76 8 8 bronze badges. MEnnabah MEnnabah 1, 1 1 gold badge 16 16 silver badges 36 36 bronze badges. You can use try I would like to know the reason why this answer get this much down-votes. As the name suggests, exceptions should only be used on exceptional cases. HelioSantos Isn't this an exceptional situation for which the language is not supplying proper solution?
Show 2 more comments. Nick Lewis Nick Lewis 4, 1 1 gold badge 19 19 silver badges 22 22 bronze badges. But it may choose any statement associated with a true Boolean expression. So, the correctness of the program cannot depend on which statement is chosen among those associated with true Boolean expressions. If none of the Boolean expressions is true, a run-time error occurs that causes program termination. This forces the programmer to consider and list all possibilities.
Consider the following example:. If i is equal to j and is not zero, a runtime error occurs because none of the conditions is true. This statement can be an elegant way of allowing the programmer to state that the order of execution, in some cases, is irrelevant. For example, to find the largest of two numbers, we can use. This computes the desired result without overspecifying the solution.
In particular, if x and y are equal, it does not matter which we assign to max. This is a form of abstraction provided by the nondeterministic semantics of the statement.
Now, consider this same process coded in a traditional programming language selector:. There is no practical difference between these two statements. The first assigns x to max when x and y are equal; the second assigns y to max in the same circumstance. This choice between the two statements complicates the formal analysis of the code and the correctness proof of it.
This is one of the reasons why guarded commands were developed by Dijkstra. The semantics of this statement is that all Boolean expressions are evaluated on each iteration.
If more than one is true, one of the associated statements is nondeterministically perhaps randomly chosen for execution, after which the expressions are again evaluated.
When all expressions are simultaneously false, the loop terminates. Without guarded commands, one straightforward solution is to put the four values into an array, sort the array, and then assign the values from the array back into the scalar variables q1 , q2 , q3 , and q4. While this solution is not difficult, it requires a good deal of code, especially if the sort process must be included.
Now, consider the following code, which uses guarded commands to solve the same problem but in a more concise and elegant way. Program verification is virtually impossible when goto statements are used. Verification is greatly simplified if. The axiomatic semantics of guarded commands is conveniently specified Gries, It should be obvious, however, that there is considerably increased complexity in the implementation of the guarded commands over their conventional deterministic counterparts.
We have described and discussed a variety of statement-level control structures. A brief evaluation now seems to be in order. This result has been used by those who wish to ban unconditional branching altogether. Of course, there are already sufficient practical problems with the goto to condemn it without also using a theoretical reason.
One of the main legitimate needs for gotos—premature exits from loops—can be met with highly restricted branch statements, such as break.
No widely used language has yet taken that step; furthermore, we doubt that any ever will, because of the negative effect on writability and readability. Programs written with only selection and pretest logical loops are generally less natural in structure, more complex, and therefore harder to write and more difficult to read. For example, the C multiple selection structure is a great boost to C writability, with no obvious negatives. Another example is the counting loop structure of many languages, especially when the statement is simple, as in Ada.
It is not so clear that the utility of many of the other control structures that have been proposed is worth their inclusion in languages Ledgard and Marcotty, This question rests to a large degree on the fundamental question of whether the size of languages must be minimized. Both Wirth and Hoare strongly endorse simplicity in language design.
In the case of control structures, simplicity means that only a few control statements should be in a language, and they should be simple. The rich variety of statement-level control structures that have been invented shows the diversity of opinion among language designers.
0コメント