This is a long but prescient 1974 article by Donald Knuth on the tradeoffs between readability and performance. Following are some choice quotes to entice you to read the whole thing.
I should confess that the title of this article was chosen primarily to generate attention. There are doubtless some readers who are convinced that abolition of go to statements is merely a fad, and they may see this title and think, "Aha! Knuth is rehabilitating the go to statement, and we can go back to our old ways of programming again." Another class of readers will see the heretical title and think, "When are diehards like Knuth going to get with it?" I hope that both classes of people will read on and discover that what I am really doing is striving for a reasonably well balanced viewpoint about the proper role of go to statements. I argue for the elimination of go to's in certain cases, and for their introduction in others.
...
[I]t seems that fanatical advocates of the New Programming are going overboard in their strict enforcement of morality and purity in programs. Sooner or later people are going to find that their beautifully-structured programs are running at only half the speed--or worse--of the dirty old programs they used to write, and they will mistakenly blame the structure instead of recognizing what is probably the real culprit--the system overhead caused by typical compiler implementation of Boolean variables and procedure calls.
...
At the present time I think we are on the verge of discovering at last what programming languages should really be like. I look forward to seeing many responsible experiments with language design during the next few years; and my dream is that by 1984 we will see a consensus developing for a really good programming language (or, more likely, a coherent family of languages). Furthermore, I'm guessing that people will become so disenchanted with the languages they are now using--even COBOL and FORTRAN-- that this new language, UTOPIA84, will have a chance to take over. At present we are far from that goal, yet there are indications that such a language is very slowly taking shape.
...
My own programming style has of course changed during the last decade, according to the trends of the times (e.g., I'm not quite so tricky anymore, and I use fewer go to's), but the major change in my style has been due to this inner loop phenomenon. I now look with an extremely jaundiced eye at every operation in a critical inner loop, seeking to modify my program and data structure (as in the change from Example 1 to Example 2) so that some of the operations can be eliminated. The reasons for this approach are that: a) it doesn't take long, since the inner loop is short; b) the payoff is real; and c) I can then afford to be less efficient in the other parts of my programs, which therefore are more readable and more easily written and debugged.
...
There is no doubt that the grail of efficiency leads to abuse. Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified. It is often a mistake to make a priori judgments about what parts of a program are really critical, since the universal experience of programmers who have been using measurement tools has been that their intuitive guesses fail. After working with such tools for seven years, I've become convinced that all compilers written from now on should be designed to provide all programmers wit...
You missed my favorite quote from any computer science paper:
"Axiomatics of Jumps
[...]
"Just recently, however, Hoare has shown that there is, in fact, a rather simple way to give an axiomatic definition of go to statements; indeed, he wishes quite frankly that it hadn't been quite so simple. For each label L in a program, the programmer should state a logical assertion α(L) which is to be true whenever we reach L. Then the axioms
{α(L)} go to L {false}
plus the rules of inference
{α(L)} S {P} ⊢ {α(L)} L:S {P}
are allowed in program proofs, and all properties of labels and go to's will follow if the α(L) are selected intelligently. One must, of course, carry out the entire proof using the same assertion α(L) for each appearance of the label L, and some choices of assertions will lead to more powerful results than others.
"Informally, α(L) represents the desired state of affairs at label L; this definition says essentially that a program is correct if α(L) holds at L and before all "go to L" statements, and that control never "falls through" a go to statement to the following text. Stating the assertions α(L) is analogous to formulating loop invariants. Thus, it is not difficult to deal formally with tortuous program structure if it turns out to be necessary; all we need to know is the "meaning" of each label."
(p. 289-290)
Not only does "he wishes quite frankly that it hadn't been quite so simple" make me giggle like a schoolgirl for several minutes every time I see it, but it's also a really beautiful formalism.
You seem to be addressing the title rather than the meat of the paper. If it's the same version as is included in Literate Programming (as I believe it to be), I highly recommend reading through it.
From the introductory quotes: "Do you suffer from painful elimination?" Love Knuth's sly sense of humor. As brilliant as he is, he refuses to take himself too seriously. A model for us all.
7 comments
[ 2.9 ms ] story [ 25.9 ms ] thread-------------------------------------------------------
I should confess that the title of this article was chosen primarily to generate attention. There are doubtless some readers who are convinced that abolition of go to statements is merely a fad, and they may see this title and think, "Aha! Knuth is rehabilitating the go to statement, and we can go back to our old ways of programming again." Another class of readers will see the heretical title and think, "When are diehards like Knuth going to get with it?" I hope that both classes of people will read on and discover that what I am really doing is striving for a reasonably well balanced viewpoint about the proper role of go to statements. I argue for the elimination of go to's in certain cases, and for their introduction in others.
...
[I]t seems that fanatical advocates of the New Programming are going overboard in their strict enforcement of morality and purity in programs. Sooner or later people are going to find that their beautifully-structured programs are running at only half the speed--or worse--of the dirty old programs they used to write, and they will mistakenly blame the structure instead of recognizing what is probably the real culprit--the system overhead caused by typical compiler implementation of Boolean variables and procedure calls.
...
At the present time I think we are on the verge of discovering at last what programming languages should really be like. I look forward to seeing many responsible experiments with language design during the next few years; and my dream is that by 1984 we will see a consensus developing for a really good programming language (or, more likely, a coherent family of languages). Furthermore, I'm guessing that people will become so disenchanted with the languages they are now using--even COBOL and FORTRAN-- that this new language, UTOPIA84, will have a chance to take over. At present we are far from that goal, yet there are indications that such a language is very slowly taking shape.
...
My own programming style has of course changed during the last decade, according to the trends of the times (e.g., I'm not quite so tricky anymore, and I use fewer go to's), but the major change in my style has been due to this inner loop phenomenon. I now look with an extremely jaundiced eye at every operation in a critical inner loop, seeking to modify my program and data structure (as in the change from Example 1 to Example 2) so that some of the operations can be eliminated. The reasons for this approach are that: a) it doesn't take long, since the inner loop is short; b) the payoff is real; and c) I can then afford to be less efficient in the other parts of my programs, which therefore are more readable and more easily written and debugged.
...
There is no doubt that the grail of efficiency leads to abuse. Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified. It is often a mistake to make a priori judgments about what parts of a program are really critical, since the universal experience of programmers who have been using measurement tools has been that their intuitive guesses fail. After working with such tools for seven years, I've become convinced that all compilers written from now on should be designed to provide all programmers wit...
Strangley, these often feel more "powerful" to me than the structured languages I use. Especially when writing small programs.
"Axiomatics of Jumps
[...]
"Just recently, however, Hoare has shown that there is, in fact, a rather simple way to give an axiomatic definition of go to statements; indeed, he wishes quite frankly that it hadn't been quite so simple. For each label L in a program, the programmer should state a logical assertion α(L) which is to be true whenever we reach L. Then the axioms
plus the rules of inference are allowed in program proofs, and all properties of labels and go to's will follow if the α(L) are selected intelligently. One must, of course, carry out the entire proof using the same assertion α(L) for each appearance of the label L, and some choices of assertions will lead to more powerful results than others."Informally, α(L) represents the desired state of affairs at label L; this definition says essentially that a program is correct if α(L) holds at L and before all "go to L" statements, and that control never "falls through" a go to statement to the following text. Stating the assertions α(L) is analogous to formulating loop invariants. Thus, it is not difficult to deal formally with tortuous program structure if it turns out to be necessary; all we need to know is the "meaning" of each label."
(p. 289-290)
Not only does "he wishes quite frankly that it hadn't been quite so simple" make me giggle like a schoolgirl for several minutes every time I see it, but it's also a really beautiful formalism.
Not that anyone would ever do it in practice....
Let's say you want to write the equivalent of this C code:
in FORTRAN IV. Here's how I was taught to do it, back in the not-so-good old days before my college even had a C compiler: