Go To Statement Considered Harmful
Learning Objectives
- You know of Dijkstra’s famous letter criticizing the GOTO statement.
- You can recognize issues that the use of GOTO can create in code structure.
- You understand the historical context of GOTO and how it fit early programming.
- You know of the Böhm-Jacopini theorem and its implications.
The Famous Letter
In 1968, Edsger W. Dijkstra wrote an opinion piece to the Communications of the ACM titled Go To Statement Considered Harmful. Dijkstra’s opening sentence included the observation that “the quality of programmers is a decreasing function of the density of go to statements in the programs they produce”. In effect, he argued that the more GOTO statements a programmer used, the worse they were at the craft.
The key argument was that GOTO statements lead to unstructured code that is hard to read, reason about, and maintain. The debate, in part, contributed to the evolution of programming languages that followed.
Funnily enough, there are plenty of articles titled “Considered Harmful” that followed Dijkstra’s original letter, applying the same critique to various programming practices. Some folks at Aalto University have even shortened the the phrase to just “Considered”, see Break Statement Considered.
Dijkstra's Main Argument
0 / 4 points
What was Dijkstra’s main criticism of the GOTO statement in his 1968 letter?
What’s Wrong with GOTO?
You’ve just built an interpreter with GOTO! Was this a mistake? Not at all - understanding GOTO by implementing it gives you deeper appreciation for why the field has moved beyond it.
Let’s explore the problems GOTO creates through concrete examples.
Spaghetti Code
Consider this BASIC program:
10 GOTO 8020 PRINT "Step 2"30 GOTO 6040 PRINT "Step 1"50 GOTO 2060 PRINT "Step 3"70 GOTO 9080 GOTO 4090 PRINT "Done"100 ENDTo solve the question “What order do the PRINT statements execute?”, you have to trace through the jumps. When you try to read it, your brain has to simulate the execution flow mentally. The steps are not in a linear order, and there are also no clear structures indicating loops or conditionals.
The flow is:
10 -> 80 -> 40 -> Print "Step 1" -> 50 -> 20 -> Print "Step 2" -> 30 -> 60 -> Print "Step 3" -> 70 -> 90 -> Print "Done" -> 100This is spaghetti code: the code is messy, the control flow is tangled, and the code is unstructed. Reading it requires mentally executing the program.
Spaghetti Code Definition
0 / 3 points
What is “spaghetti code” in the context of GOTO statements?
Reasoning About State and No Clear Loop Invariants
Consider this loop:
10 LET I = 020 LET I = I + 130 PRINT I40 IF I < 10 THEN 2050 ENDTo solve the question “What is the value of I at line 30?”, you have to trace through the loop iterations. Each time you reach line 30, I has a different value depending on how many times you’ve looped.
You might think that the answer would be “it could be any value from 1 to 10, depending on which iteration you’re in!”. However, in any realistic BASIC program, it’s not as simple. The actual answer is “it could be anything, because with GOTO you could jump into the middle of the loop from anywhere else in the program”.
A loop invariant is a property that’s always true at a specific point in a loop.
With structured loops:
for i in 1..=10 { // Invariant: 1 <= i <= 10 println!("{}", i);}The loop invariant is clear: at the start of each iteration, i is between 1 and 10. After the loop, i no longer exists.
Loop Invariants
0 / 4 points
What is a loop invariant?
Unstructured Error Handling
Because the programs do not have structured control flow, error handling with GOTO can also become messy. In the program below, the INPUT statement reads a number, and if it’s negative, it jumps to an error handler.
10 LET X = 020 INPUT X30 IF X < 0 THEN 10040 LET Y = 100 / X50 PRINT Y60 GOTO 20100 PRINT "Error: negative number"110 GOTO 20You’d never know that the line 100 is an error handler just by briefly looking at it. There’s no structure indicating “this is error handling code.”
Code Duplication
10 INPUT X20 IF X < 0 THEN 10030 LET Y = X * 240 PRINT Y50 GOTO 200100 REM Error handling110 PRINT "Error: negative"120 LET Y = 0130 PRINT Y140 GOTO 200Lines 40 and 130 duplicate PRINT Y. Without functions, you can’t reuse code - you GOTO different locations that repeat the same logic.
GOTO Made Sense
Well, if GOTO is so bad, why did early programming languages include it? There are several historical reasons.
Assembly Language Perspective
First, early programming was done in assembly language, and GOTO built on top of the mentality of assembly language. Assembly has conditional and unconditional jumps:
MOV AX, 0 ; i = 0loop: INC AX ; i++ CALL PRINT ; print(i) CMP AX, 10 ; compare i to 10 JL loop ; jump if less HLT ; endThis is just GOTO by another name! Early high-level languages like FORTRAN and BASIC were, in a sense, thin wrappers over assembly that sought to make programming easier.
Limited Memory
Early computers had few kilobytes of memory, no stack (or a tiny stack), and function calls were expensive. Structured constructs like loops and functions require more instructions than a simple GOTO.
The GOTO statement could be implemented simply as a jump instruction, which was efficient in terms of both memory and execution time. A function call, on the other hand, requires saving the return address, managing a call stack, and possibly passing parameters, which adds overhead.
Batch Processing
Early programming was based on batch jobs. Programmers wrote code on punch cards, the punch cards were delivered to a data center, a data center operator fed the punch cards into a computer, the computer processed the cards one by one, receiving no user input during execution, and finally the operator collected the printout of the submitted jobs.
Programmers received the results from their code hours or days later. There was no interactive debugging or iterative development.
If a problem was found, the programmer had to fix the code, punch new cards, and resubmit the job. GOTO statements made it easier to write quick-and-dirty hacks to get the job done in this environment; one could, for example, rewrite one card from the middle of a batch job to fix a bug, where the card represented a GOTO statement to skip over faulty code and do the execution in a new set of cards that would be added to the end of the program. At the end of the new set of cards, there would be a GOTO back to the original program flow.
Assembly Language Connection
0 / 3 points
Why did GOTO make sense from an assembly language perspective?
The Böhm-Jacopini Theorem
The original version of BASIC was released in 1964, four years before Dijkstra’s letter. At that point, GOTO was a natural fit for the language design, and structured programming as we currently know it was not yet mainstream.
ALGOL, which is the first language to introduce structured programming concepts like block structure and nested control flow, was also released in 1960. However, its adoption was limited compared to FORTRAN and BASIC.
In 1966, Corrado Böhm and Giuseppe Jacopini proved an important theorem that further supported Dijkstra’s argument. The Böhm-Jacopini theorem states that any program can be written using only three control structures: sequence, selection (if/then/else), and iteration (while loops), without the need for GOTO statements.
This means that GOTO is not necessary for expressing any computation. While removing GOTO can lead to more verbose code in some cases, it encourages better structure and readability.
Böhm-Jacopini Theorem
0 / 3 points
What does the Böhm-Jacopini theorem state?
Summary
In this chapter, we briefly discussed the GOTO controversy. To summarize:
- Dijkstra’s letter critiqued GOTO for leading to unstructured code.
- GOTO creates problems: spaghetti code, unclear state, no invariants.
- Structured programming replaces GOTO with sequence, selection, iteration.
- Historical context: GOTO made sense for early computers due to assembly roots, limited memory, and batch processing.
- Böhm-Jacopini theorem showed that any program can be written without GOTO.
ALGOL and History
0 / 3 points
What was significant about ALGOL in the history of structured programming?