Fact-checked by Grok 2 weeks ago

Structured programming

Structured programming is a that seeks to improve the clarity, quality, and development efficiency of computer programs by restricting to a small set of structured constructs—sequence, selection, and —while eschewing unstructured jumps such as the goto statement. This approach emphasizes logical hierarchy, modularity, and top-down design to make code more readable, maintainable, and less prone to errors. The theoretical foundation of structured programming rests on the , also known as the Böhm–Jacopini theorem, which proves that any can be expressed using only the three basic control structures mentioned above, without reliance on arbitrary branching. Formally stated in a 1966 paper by Corrado Böhm and Giuseppe Jacopini, the theorem demonstrates that equivalent structured programs can always replace unstructured ones, provided auxiliary variables are allowed to eliminate side effects from jumps. This result shifted focus from low-level machine instructions to higher-level abstractions in programming language design. The paradigm gained prominence in the late 1960s amid growing concerns over software complexity during the "," where large-scale programs became notoriously difficult to debug and maintain. Edsger W. Dijkstra's influential 1968 letter, "Go To Statement Considered Harmful," catalyzed widespread adoption by critiquing the for fostering "" that obscures program logic and hinders human comprehension. Dijkstra argued that disciplined use of structured constructs enables better reasoning about program behavior, reducing the intellectual burden on developers. Key principles of structured programming include sequential execution for straightforward step-by-step processing, selection via conditional statements (e.g., ) for decision-making, and through loops (e.g., while or for) for repetition, all nested hierarchically to form compound statements. These elements promote single-entry, single-exit blocks, avoiding the multiple paths that complicate analysis in unstructured code. Proponents like further advanced the paradigm through languages such as Pascal (1970), designed explicitly to enforce structured practices and support stepwise refinement. The impact of structured programming extends to modern software engineering, influencing procedural languages like C and serving as a precursor to object-oriented and functional paradigms. While critics like Donald Knuth noted scenarios where limited goto use might enhance efficiency without sacrificing clarity, the core tenets have become foundational, underpinning tools for code analysis, refactoring, and verification.

Core Elements

Control Structures

In structured programming, control structures provide the mechanisms for directing the flow of execution in a , ensuring that proceeds in a predictable and hierarchical manner without arbitrary jumps. These structures are foundational, as they replace unstructured branching with well-defined patterns that promote clarity and . The core structures—, , and —form the basis for all computational tasks, as established by the theoretical sufficiency demonstrated in early work on program structuring. Sequence represents the default control flow, where statements are executed linearly one after another in the order they appear in the source code. This straightforward progression assumes no interruptions, allowing programmers to build basic operations like assignments or function calls in a natural reading order. For example, in :
statement1;
statement2;
statement3;
Here, execution proceeds from statement1 to statement3 without deviation, forming the building blocks for more complex logic. Selection enables decision-making by evaluating conditions and choosing between alternative paths of execution. The primary form is the conditional statement, such as , which tests a and executes one block if true or another if false. Nested selections allow for multi-level decisions, where an if-else can contain further if-else constructs, creating a tree-like . in these structures means that selection blocks do not overlap with other control structures in unintended ways, maintaining clear boundaries. A example illustrates this:
if condition then
    execute block A
else
    execute block B
end if
This ensures that only one path is taken based on the , with a single entry point at the if and a single exit after the else. Iteration provides repetition of blocks based on a or count, allowing efficient handling of repetitive tasks. Pre-test loops, like while-do, evaluate the before executing the body, ensuring the loop may not run at all if the is initially false. Count-controlled loops, such as for-do, iterate a fixed number of times, often initializing a , testing it against a limit, and incrementing it. Both types emphasize single entry and exit points to avoid confusion in flow. For instance, a while-do :
while condition do
    execute loop body
end while
And a for-do example:
for i from 1 to n do
    execute loop body
end for
These structures confine repetition to a defined , preventing scattered paths. The avoidance of statements is central to structured programming, as unrestricted jumps lead to ""—tangled, non-hierarchical flows that obscure program logic and hinder maintenance. Instead, structures compose hierarchically, where each can nest within others without crossing boundaries, as advocated in critiques of unstructured practices. This composition aligns with the Bohm-Jacopini theorem, which proves that , selection, and suffice for any . Subroutines can modularize complex flows by encapsulating these structures into reusable units. By enforcing single entry and exit points and hierarchical nesting, these control structures enhance provability, allowing techniques to analyze correctness level by level, and improve readability, making easier to understand and debug through its resemblance to problem-solving hierarchies.

Subroutines

In structured programming, subroutines serve as fundamental modular components, consisting of named blocks of that encapsulate specific tasks and can be invoked repeatedly from other parts of the through explicit calls. These blocks promote decomposition by isolating functionality, with parameters enabling the passing of input and, in some cases, the return of output values to the caller. This approach contrasts with monolithic by enforcing clear interfaces between reusable units and the main . Subroutines are categorized into two primary types: procedures, which perform actions without returning a value (often called void procedures), and functions, which compute and return a specific result. Procedures are ideal for operations like updating structures or performing , while functions suit calculations such as mathematical evaluations or transformations. Parameter passing mechanisms further distinguish subroutine behavior: pass-by-value creates a copy of the argument, protecting the original from modification but potentially increasing overhead for large ; pass-by-reference, conversely, passes an alias to the original , allowing efficient updates but risking unintended side effects if not managed carefully. These types and mechanisms are integral to maintaining and predictability in structured designs. The adoption of subroutines yields significant benefits, including enhanced abstraction that conceals implementation details behind simple interfaces, thereby reducing overall program complexity and cognitive load on developers. By enabling top-down design—where high-level tasks are progressively refined into detailed subroutines—programmers can build hierarchical structures that mirror problem-solving processes, fostering maintainability and scalability. Subroutines also eliminate code duplication by allowing shared logic to be defined once and reused, while their modular nature facilitates isolated unit testing, where individual components can be verified independently without executing the entire program. Within subroutines, control structures like sequences, selections, and iterations manage internal logic, and blocks provide lexical scoping for local variables to prevent namespace pollution. To illustrate, consider a declaration and of a simple for computing the sum of two s:
[procedure](/page/Procedure) add([integer](/page/Integer)s x, y: [integer](/page/Integer)) returns sum: [integer](/page/Integer)
begin
    sum := x + y
end

// [Invocation](/page/Invocation) in main program
result := add(5, 3)
Here, parameters x and y are passed by value, and the returns the computed sum. For a procedure without return, such as printing a :
procedure print_message(message: string)
begin
    output(message)
end

// Invocation
print_message("Hello, World!")
Recursion extends subroutine utility by allowing a subroutine to invoke itself, enabling elegant solutions to problems like tree traversals or combinatorial generation, as in the where a places row by row, on conflicts:
procedure place_queens(row: integer)
begin
    if row > 8 then
        print_configuration()
    else
        for col := 1 to 8 do
            if square[row, col] is safe then
                place queen at [row, col];
                place_queens(row + 1);
                remove queen from [row, col]
end
However, recursion demands caution, as excessive depth can exhaust the call , leading to errors; base cases must ensure termination, and tail-recursive forms or iterative alternatives are preferable for deep recursions to mitigate this risk.

Blocks

In structured programming, blocks serve as fundamental units for grouping statements and declarations, providing delimited scopes that enhance modularity and clarity. A block is typically introduced by a keyword such as begin and terminated by end, forming a compound statement that encapsulates a sequence of executable instructions along with any local declarations. This structure, first formalized in , allows for the creation of self-contained code segments where variables and labels are confined to the block's lifetime, promoting disciplined program organization. Local variables declared within a are automatically allocated upon entry and deallocated upon exit, ensuring their visibility is restricted to that and preventing interference with outer contexts. Scoping rules dictate that identifiers declared ly override any outer declarations with the same name, while nonlocal identifiers retain their external meanings; this hierarchical resolution supports nested , where inner blocks can declare their own variables without affecting enclosing ones. Labels within blocks are inherently , further isolating the block's internal logic. Such mechanisms are crucial for automatic storage management, as variables cease to exist once the block completes, reducing overhead and errors from unintended reuse. Blocks play a pivotal in encapsulation by hiding internal data and operations from the rest of the program, thereby preventing namespace pollution where variables might conflict or expose details unnecessarily. This isolation fosters reusable code components and simplifies maintenance, as changes within a do not propagate outward unless explicitly intended. Additionally, block structure supports by allowing procedures—often realized as blocks with parameters—to call themselves without violations, as each recursive invocation establishes a fresh local environment via static scoping. To illustrate, consider the following example adapted from conventions, demonstrating nested blocks and scope resolution:
begin
    integer x := 1;
    if condition then
        begin
            integer x := 2;  // Local to inner block, shadows outer x
            output(x);  // Prints 2
        end;
    output(x);  // Prints 1, outer x unchanged
end
Here, the inner block declares its own x, which is inaccessible after exit, preserving the outer x and exemplifying lexical scoping. Blocks integrate seamlessly with control structures like sequences, selections, and iterations to uphold the single-entry/single-exit principle central to structured programming, ensuring that execution flows predictably from entry to exit without unstructured jumps. This composition allows complex programs to be built as hierarchies of such units, where a block might enclose an or , maintaining overall discipline in . Subroutines are frequently implemented as parameterized blocks to achieve similar scoping benefits.

Structured Programming Languages

Defining Features

Structured programming languages are distinguished by their provision of disciplined primitives, emphasizing sequence, selection, and iteration while generally discouraging unconditional jumps such as the statement or equivalent mechanisms that allow arbitrary transfers of . This approach promotes hierarchical, single-entry/single-exit structures to avoid complex, hard-to-maintain code, though many languages include optionally for flexibility rather than embedding restrictions that prevent it entirely. Central to these languages is the use of three fundamental control primitives: for linear execution, selection (such as ) for conditional branching, and (such as do-while or while-do loops) for repetition. These primitives form the building blocks of all control structures, promoting modularity and readability by mirroring the logical decomposition of problems into nested, composable units. This approach builds on core elements like control structures and blocks, which serve as foundational requirements for enforcing program discipline. Many structured programming languages incorporate strong typing, where variables and expressions are rigorously type-checked at to prevent type mismatches and ensure semantic consistency. Coupled with static scoping, which determines visibility based on lexical nesting rather than dynamic execution paths, these features enable compile-time detection of errors. However, strong typing and static scoping are not universal requirements of the . This combination facilitates early error identification and supports the overall goal of producing verifiable, reliable software. In some designs, such as those by , a key principle is the of features, particularly the independence of control structures from data structures, allowing programmers to combine them without unexpected interactions or special cases. This design minimizes complexity by ensuring that modifications to control logic do not inadvertently affect data handling, and vice versa, thereby enhancing expressiveness while maintaining simplicity. contributes to the language's suitability for structured , as seen in efforts to create clean, hierarchical program architectures. To aid in design and verification, structured programming employs techniques such as flowcharts and structured English. Flowcharts visually represent control flow using standardized symbols for sequence, selection, and iteration, allowing designers to validate the hierarchical structure before implementation. Structured English, a restricted form of natural language using only the approved control primitives, provides a textual specification that bridges informal requirements and formal code, ensuring alignment with the language's syntactic constraints. These methods, developed in response to the post-1960s push for improved program reliability, enable systematic review and proof of correctness without relying on unstructured elements.

Historical and Modern Examples

, published in 1960, is widely regarded as the first structured programming language, introducing key features such as block structure for scoping and call-by-name parameter passing. The block structure allowed declarations and statements to be grouped within begin-end delimiters, enabling nested scopes that limited variable visibility and promoted modular code organization. Call-by-name treated parameters as textual substitutions evaluated each time they were referenced, supporting flexible calls while providing structured , though it also includes a go to statement. Pascal, defined by in 1970, became a cornerstone for teaching structured programming due to its strict enforcement of control structures, although it includes a statement that is discouraged. Intended for educational use, it emphasized readability and reliability through features like strong typing, procedural abstraction, and compound statements, influencing curricula worldwide. , developed by in 1972 at , adopted structured elements from and , including functions, loops, and conditionals, but offered flexibility with optional for low-level control in . This balance made suitable for Unix development while encouraging structured practices. In the 1980s, Ada emerged as a structured language tailored for safety-critical systems, standardized in 1983 under U.S. Department of Defense auspices to promote reliability in embedded and real-time applications. It extended structured principles with strong typing, packages for modularity, and tasking for concurrency, reducing errors in domains like . Java, released by in 1995, integrated structured programming with object-oriented paradigms, mandating classes and methods while providing control structures like loops and conditionals without . Its design ensured portability and safety, blending procedural structure with encapsulation and inheritance. The evolution of structured programming is evident in , first released by in 1991, which preserves core structured elements like sequential execution, selection, and while introducing higher-level abstractions such as list comprehensions and functions as first-class objects. These features maintain and without compromising the no-goto discipline, allowing concise expression of complex logic. Python's indentation-based blocks reinforce structured flow, adapting the paradigm to scripting and data-intensive tasks. To illustrate structured principles, consider a simple summation task. In , an unstructured approach might rely on labels and jumps, but structured code uses a for-loop within a block:
begin
  integer sum, i;
  sum := 0;
  for i := 1 step 1 until 10 do
    sum := sum + i;
  outinteger(1, sum)
end
This avoids arbitrary jumps, localizing variables to the block. In Pascal, a while-loop replaces potential gotos for the same task:
program SumExample;
var
  sum, i: integer;
begin
  sum := 0;
  i := 1;
  while i <= 10 do
  begin
    sum := sum + i;
    i := i + 1
  end;
  writeln('Sum: ', sum)
end.
The structured version clarifies the iteration boundary, enhancing maintainability over a goto-based equivalent that could obscure flow. Similarly, in C, a for-loop embodies structure:
#include <stdio.h>
int main() {
    int sum = 0, i;
    for (i = 1; i <= 10; i++) {
        sum += i;
    }
    printf("Sum: %d\n", sum);
    return 0;
}
Although C permits goto for early exits, the loop form aligns with structured ideals, preventing and improving debuggability compared to unconditional jumps.

Historical Development

Theoretical Foundations

The theoretical foundations of structured programming rest on the Böhm–Jacopini theorem, which demonstrates the sufficiency of a minimal set of control structures for expressing any . Formulated by Corrado Böhm and Giuseppe Jacopini in 1966, the theorem states that any algorithm representable as a can be equivalently implemented using only sequential composition, conditional alternation (), and iterative repetition (while loops), without reliance on unstructured jumps like statements. This result assumes basic , where the constructs align with Turing-complete capabilities, ensuring no loss of expressive power. The canonical forms of these constructs are as follows:
  • Sequential composition: Executes statements in order.
    S1;
    S2;
    where S1 and S2 are subprograms.
  • Conditional alternation: Selects between two paths based on a condition B.
    if B then
        S1
    else
        S2
    where S1 executes if B is true, and S2 otherwise.
  • Iterative repetition: Repeats a subprogram while a condition holds.
    while B do
        S
    where S executes repeatedly as long as B remains true.
These primitives form the basis for nesting and combining to achieve arbitrary . The proof of the involves a constructive transformation of arbitrary —potentially containing unstructured branches—into equivalent structured programs. This is achieved by systematically eliminating improper connections through techniques such as introducing state variables to track control points or nesting conditional and structures to simulate jumps, ensuring the resulting program preserves the original semantics while adhering to the three constructs. For instance, a multi-entry point in a can be resolved by embedding it within a that uses conditionals to route execution appropriately. Related work by in 1974 refined these ideas, arguing that while the theorem proves the eliminability of statements, judicious use of in limited cases can enhance program clarity and efficiency without compromising overall structure, particularly when standard loops lead to excessive nesting. The theorem's emphasis on structured constructs profoundly influenced program correctness verification, enabling frameworks like , introduced by C. A. R. Hoare in 1969, which uses preconditions and postconditions to formally prove program properties through inference rules tailored to sequential, conditional, and iterative statements.

The Goto Debate

The debate over the goto statement emerged as a pivotal controversy in the late , centering on its role in producing maintainable and understandable code. In 1968, published a seminal letter in Communications of the ACM titled "Go To Statement Considered Harmful," arguing that the unrestricted use of goto severely undermines program clarity and verifiability. Dijkstra posited that goto disrupts the ability to track a program's dynamic progress through a structured , such as textual indices for statements or dynamic indices for loops and procedure calls, making it difficult to interpret variable states relative to execution flow. He observed that programmer quality inversely correlates with goto density, as it invites unstructured "" that obscures logical invariants and complicates , ultimately calling for its abolition from higher-level languages to bridge the gap between static code and dynamic processes. This provocative stance, originally submitted as "A Case Against the Goto Statement" but retitled by CACM editor to emphasize its polemical nature, ignited widespread discussion among computer scientists. Wirth, a key proponent of structured design through his work on and Pascal, amplified the letter's impact by framing it as a call to reform programming practices. C. A. R. Hoare, collaborating with Wirth on developments, had earlier advocated restricting goto to exceptional "alarm exits" rather than routine , viewing it as inferior to structured alternatives like the case construct for mirroring program dynamics without labels. Meanwhile, John Backus, who led the design of —the first high-level language to introduce goto in 1957 as a flexible transfer mechanism mimicking —represented the earlier paradigm where such statements were essential for practical coding efficiency. Counterarguments soon surfaced, most notably from Donald E. Knuth in his 1974 paper "Structured Programming with go to Statements," published in Computing Surveys. Knuth defended disciplined goto use, contending that its outright elimination could sacrifice clarity or efficiency in specific algorithms, such as optimizations where structured rewrites become verbose or slower. He analyzed examples demonstrating that goto enhances readability in scenarios like multiway branching in interpreters or eliminating deep recursion, provided invariants are maintained and abstractions are clear; for instance, in an optimized Quicksort, goto reduces stack depth from O(n) to O(log n) while saving over 25% in runtime compared to a purely recursive version. Knuth critiqued dogmatic anti-goto positions as potentially harmful, suggesting improved syntax for loops and exits could minimize its need without banning it entirely. The controversy profoundly influenced programming education, prompting a shift from assembly-like, goto-heavy curricula to structured approaches emphasizing control structures like sequences, selections, and iterations. By the mid-1970s, textbooks and courses increasingly adopted these principles, drawing from the theoretical groundwork of Böhm and Jacopini's 1966 proof of goto superfluity, to teach maintainable code over low-level control transfers. This pedagogical evolution reduced emphasis on unstructured flowcharts and promoted languages without goto, fostering habits that prioritized conceptual clarity for novice programmers. Illustrative examples highlight the debate's core tension. Consider a snippet for counting room entries, vulnerable to goto-induced tangles:
n = 0
label1: read sensor
if sensor = enter then goto label2
if sensor = exit then goto label3
goto label1
label2: n = n + 1; goto label1
label3: n = n - 1; goto label1
Here, multiple jumps create opaque flow, risking miscounts if paths intersect unexpectedly, as Dijkstra warned. A structured rewrite using loops and conditionals clarifies progress:
n = 0
while true:
    read sensor
    if sensor = enter:
        n = n + 1
    else if sensor = [exit](/page/Exit):
        n = n - 1
In contrast, Knuth's defense shines in cases like error handling, where a single goto to an block avoids duplicating cleanup code across nested structures, improving conciseness without compromising invariants.

Widespread Adoption

During the , structured programming transitioned from theoretical advocacy to a dominant in and education, driven by influential textbooks and international recommendations. Seminal works such as "Structured Programming" by , , and Charles Antony Richard Hoare (1972) provided foundational guidance on control structures and , emphasizing and verifiability over unstructured jumps. By the early 1980s, textbooks like Carlo Ghezzi and Mehdi Jazayeri's "Programming Language Concepts" (first edition, 1982) further promoted these principles through discussions of computation structuring and language design, influencing curricula worldwide. Concurrently, the UNESCO-IFIP "Modular Curriculum in " (developed in the late and published in 1985) explicitly recommended teaching algorithms and structured programming as core modules, aiming to standardize introductory education across member states and foster modular, error-resistant coding practices. In industry, structured programming's adoption was accelerated by its application to large-scale projects, demonstrating tangible benefits in reliability and efficiency. At , researcher Harlan Mills championed the paradigm in the early , applying it to complex systems such as the Information Bank, where chief programmer teams produced code with exceptionally low error rates—one detected error per 10,000 lines—compared to traditional methods. This approach influenced rewrites and maintenance of legacy systems like OS/360, where structured techniques reduced complexity in modular components, paving the way for standards such as (ratified in 1989), which formalized support for blocks, loops, and conditionals to enforce structured . By the late , these practices had permeated major organizations, with empirical studies confirming significant productivity gains for structured codebases. Educationally, the paradigm led to a marked decline in goto statement usage, as instructors shifted toward for algorithm design and stepwise refinement for implementation. Niklaus Wirth's 1971 paper on stepwise refinement, which decomposes problems into hierarchical subtasks, became a cornerstone of teaching methodologies, widely adopted in university courses by the mid-1970s to promote top-down design and reduce debugging efforts. , as an informal notation bridging and code, facilitated this transition, enabling students to outline logic without syntax distractions and aligning with structured principles; its integration into textbooks and curricula contributed to a drop in unstructured constructs like in student programs by the early . The global spread of structured programming varied by region, reflecting linguistic and institutional differences. In , ALGOL's block structures and , introduced in 1960, provided a natural foundation, leading to rapid adoption in academic and research settings through languages like Pascal; by the 1970s, it influenced national curricula in countries such as the and . In the United States, where dominated scientific computing, evolution toward structured features—such as DO loops and in 77 (1978)—bridged the gap, supported by industry leaders like , though initial resistance from legacy codebases slowed full integration until the . Metrics from 1970s studies, including Mills' projects, underscored the impact by showing lower bug densities in structured code than unstructured equivalents, informing software reliability efforts such as at and validating the paradigm's role in mission-critical systems.

Deviations and Extensions

Early Exit Mechanisms

In structured programming, early exit mechanisms provide limited, localized ways to interrupt within loops or subroutines, serving as pragmatic extensions to the core principles of sequential, selective, and iterative composition without introducing the anarchy of unrestricted jumps. These mechanisms, including break and continue for loops and return for subroutines, emerged in languages influenced by the structured programming movement, such as derivatives and , where they were tolerated to address common programming patterns that would otherwise require awkward restructuring or code duplication. The break statement enables premature termination of the innermost enclosing or switch construct, effectively exiting to the code immediately following the structure. Similarly, the continue statement skips the remainder of the current iteration in a , advancing directly to the next evaluation of the loop condition. Both originated in early high-level languages like and were adapted into during its development in the early 1970s, where break also serves to exit switch cases, evolving from ALGOL-inspired switch mechanisms. These constructs deviate slightly from pure nesting by allowing internal exits but maintain traceability in graphs, preserving the single-entry, single-exit ideal at higher levels. Their rationale lies in enhancing and for practical scenarios, such as the "loop-and-a-half" problem—where input requires an initial read before testing a —or sequential searches, without forcing verbose nesting or duplication. Empirical studies, including one on novice programmers using a Pascal variant with a leave statement (analogous to break), showed that such exits led to fewer errors and more intuitive code compared to strictly nested alternatives. Guidelines for their use emphasize restriction to the innermost to avoid complicating analysis: breaks and continues should target only the immediate enclosing , ensuring the overall remains hierarchical and verifiable. For example, consider a pseudocode implementation of a sequential search in a list, where break allows early termination upon finding the key:
function findIndex(list, key):
    for i from 0 to length(list) - 1:
        if list[i] == key:
            return i  // Early return combines exit with value
        // Additional processing...
    return -1  // Not found
Without break or early return, this would require nesting the entire search logic inside a conditional or duplicating the not-found return, reducing clarity. In contrast, a fully nested version without early exits might look like:
function findIndexNested(list, key):
    found = false
    index = -1
    i = 0
    while i < length(list) and not found:
        if list[i] == key:
            found = true
            index = i
        else:
            i = i + 1
    return index
The early exit version is more concise for this common case, aligning with Knuth's observation that judicious internal exits can simplify algorithms without undermining structured discipline. The return statement, meanwhile, permits immediate exit from a subroutine upon computing its result, often mid-loop, returning a value to the caller. This was standard in structured languages like Pascal and C from their inception, as it confines the deviation to the subroutine's scope and avoids propagating unstructured flow outward. In search algorithms, for instance, return can signal success early, as shown in the pseudocode above, improving both performance and comprehension by separating the "happy path" from exhaustive iteration. Post-Dijkstra, such mechanisms gained acceptance as they do not equate to goto's flexibility, with no widespread evidence of misuse in educational or production code.

Exception Handling

Exception handling represents a structured extension to the control flow paradigms of structured programming, allowing programs to manage runtime errors and exceptional conditions without resorting to unstructured jumps like statements. In this approach, errors are treated as explicit events that can be raised, propagated, and caught in a predictable manner, separating execution from error recovery paths. This mechanism aligns with structured programming principles by maintaining locality of control and enabling modular error management, as opposed to scattering error checks throughout the code. The core design principle of exception handling emphasizes raising exceptions as structured signals for abnormal situations, such as invalid inputs or resource failures, which propagate up the call stack until intercepted by an appropriate handler. This avoids ad-hoc error propagation via return codes or flags, which can clutter normal logic and violate structured . In languages supporting this, exceptions are typically objects carrying diagnostic information, ensuring that error contexts are preserved during unwinding. Propagation occurs dynamically along the execution stack, allowing handlers at higher levels to perform or cleanup if lower levels cannot resolve the issue. A key construct in exception handling is the try-catch-finally block, which encapsulates potentially erroneous code (try), specifies handlers for specific exceptions (catch), and guarantees cleanup actions (finally) regardless of outcome. When an exception is raised—often via a built-in raise statement or implicitly by the —execution abandons the current block and searches enclosing scopes for matching handlers, unwinding the and invoking finally clauses to release resources like files or locks. This structure promotes robustness by ensuring deterministic error paths and resource safety, integral to structured programming's emphasis on reliable, analyzable code. Ada, standardized in 1983, introduced comprehensive tailored for safety-critical systems, where exceptions propagate via the call and handlers can reraise or declare others for categorization. Java, released in 1995, built on this with a of throwable objects (exceptions and errors), distinguishing checked exceptions (compile-time enforced) from unchecked ones, and using stack traces for propagation. Both languages employ similar stack-based mechanics, where unhandled exceptions terminate the program, enforcing . Exception handling enhances program robustness by centralizing error recovery, improving readability through , and enabling propagation to appropriate contexts without manual checks at every step. However, it introduces overhead in performance due to stack unwinding and runtime checks, and overuse can obscure , complicating static analysis and in large systems. When applied judiciously to true anomalies rather than expected conditions, it aligns with structured programming's goals without undermining predictability. For illustration, consider handling a divide-by-zero error in . In a structured exception approach:
try {
    result = numerator / denominator;
} catch (DivideByZeroException e) {
    log("[Division by zero](/page/Division_by_zero) detected");
    result = defaultValue;
} finally {
    cleanupResources();
}
This raises a DivideByZeroException if the denominator is zero, catches it to set a safe result, and ensures cleanup, maintaining flow integrity. In contrast, an unstructured alternative might use a to jump to an error label from deep within nested code, scattering labels and violating —such as checking if (denominator == 0) goto error_handler; after the division, leading to tangled paths. The structured version localizes handling and avoids such discontinuities.

Multiple Entry and State Machines

In early programming languages such as , multiple entry points allowed subroutines to be invoked at different starting locations within the same code block, facilitating shared code execution from various entry points without full duplication. This feature, specified via the ENTRY statement, enabled efficient reuse but violated the single-entry principle of structured programming by permitting non-linear . Computed GOTO statements further supported this by dynamically selecting a label from a list based on an integer expression, effectively creating branch tables for performance-critical jumps. Contemporary structured programming largely eschews true multiple entry points to maintain code clarity and analyzability, instead simulating them through switch or case statements that dispatch to appropriate code sections from a single entry. This approach aligns with the structured paradigm's emphasis on hierarchical control structures, avoiding the entanglement of entry-specific initialization that multiple entries can introduce. The debate, originating in the late 1960s, highlighted how such mechanisms complicated program verification, prompting a shift toward these simulated alternatives. Finite state machines (FSMs), essential for modeling sequential behavior in systems like protocols and controllers, are typically implemented in structured programming using a enclosing a on the current , with transitions updating the state based on inputs. This method ensures single-entry flow while approximating non-linear state transitions through conditional branching, preserving readability without explicit jumps. For efficiency in resource-constrained environments, lookup tables can replace switches, mapping state-input pairs directly to next states and actions. In domains like embedded systems and lexical parsers, however, purely structured FSM implementations can incur overhead from repeated condition checks, leading developers to employ unstructured "hacks" such as inline gotos or duplicated code for direct entry into states, trading clarity for reduced execution cycles. These deviations prioritize performance in applications where is critical, but they risk introducing bugs akin to those in unrestricted , as noted in structured coding guidelines. Modern functional languages offer as a structured to traditional FSMs, enabling concise, type-safe handling of state transitions without mutable state variables or explicit loops. In languages like or , patterns deconstruct inputs and states recursively, dispatching to handlers in a declarative manner that avoids deviations while supporting complex behaviors such as hierarchical states. This approach enhances by integrating state logic with data transformation, contrasting with imperative simulations. A representative example is translating a UML state diagram for a traffic light controller—featuring states like "," "," and "" with timed transitions—into structured code using a switch on the state enum within a main . For diagrams with multiple entry points, such as direct jumps to "" from error recovery, developers might use flags or auxiliary functions to simulate entry without true multi-entry, underscoring the tension between UML's expressive non-linearity and structured code's linear constraints.

References

  1. [1]
    Flow diagrams, turing machines and languages with only two ...
    Flow diagrams, turing machines and languages with only two formation rules. Authors: Corrado Böhm, Giuseppe Jacopini ...
  2. [2]
    [PDF] Structured Programming with go to Statements DONALD E. KNUTH
    Here is the history of the subject, as far as I have been able to trace it. The first programmer who systematically began to avoid all labels and go to state-.
  3. [3]
    What led to "Notes on Structured Programming" (EWD1308)
    Apr 21, 2008 · I was introduced to programming at the 1951 Summer School, given in Cambridge by Wilkes. Wheeler and Gill, and became in 1952 on a part-time ...
  4. [4]
    [PDF] Edgar Dijkstra: Go To Statement Considered Harmful - CWI
    Edgar Dijkstra: Go To Statement Considered Harmful. Page 2. Edgar Dijkstra: Go To Statement Considered Harmful. 2. Aus: Communications of the ACM 11, 3 ...
  5. [5]
    Structured programming: | Guide books | ACM Digital Library
    Geller M Test data as an aid in proving program correctness ... A view of program verification, ACM SIGPLAN Notices, 10:6, (534-545), Online ...
  6. [6]
    Letters to the editor: go to statement considered harmful
    First page of PDF. Formats available. You can view the full content in the ... Go To Statement Considered Harmful. Edsger Wybe Dijkstra. Read More. Comments.
  7. [7]
    None
    Below is a merged summary of subroutines, procedures, and functions in structured programming, combining all the information from the provided segments into a single, comprehensive response. To maximize detail and clarity, I will use a structured format with tables where appropriate, followed by a narrative summary that integrates the remaining details. The response retains all information mentioned across the summaries, including definitions, types, parameters, benefits, examples, page references, and URLs.
  8. [8]
    Subroutine - an overview | ScienceDirect Topics
    Subroutines allow the programmer to encapsulate code behind a narrow interface, which can then be used without regard to its implementation. Control abstraction ...
  9. [9]
    [PDF] Recursion - CS@Purdue
    ○ So, if the recursion never stops, the stack eventually runs out of space. » and a stack overflow error occurs on most systems. Page 15. Chapter 11. Java: an ...
  10. [10]
    [PDF] Report on the Algorithmic Language ALGOL 60
    Report on the Algorithmic Language ALGOL 60. J. H. WEGSTEIN. A. VAN WIJNGAARDEN. M. WOODGER. PETER NAUR (Editor). H. RUTISHAUSER. K. SAMELSON. B. VAUQUOIS. C.
  11. [11]
    block structure
    Block structure was introduced with the pro- gramming language Algol 60 [Nau 60,63] primarily to provide the ability to define local variables. Since then the ...
  12. [12]
    E.W.Dijkstra Archive: Notes on Structured Programming (EWD 249)
    In short, we are looking for a co-ordinate system in terms of which the discrete points of computation progress can be identified, and we want this coordinate ...
  13. [13]
    On orthogonality in programming languages | ACM SIGPLAN Notices
    An evaluation framework and comparative analysis of the widely used first programming languages.
  14. [14]
    [PDF] N89- 16327
    The process specification can consist of pseudo-code, flowcharts, or structured English. The DFDs model the structure of the system as a network of ...<|control11|><|separator|>
  15. [15]
    (PDF) Structured English and Decision Table - Academia.edu
    Structured English is a method used for planning programs that employs operation statements, conditional and repetition blocks, and a set of guidelines for ...
  16. [16]
    [PDF] revised report - Algol 60
    The report gives a complete defining description of the international algorithmic language ALGOL 60. This is a language suitable for expressing a large class of.
  17. [17]
    [PDF] Block-structured procedural languages Algol and Pascal
    Intended to be a general purpose programming language, with emphasis on scientific and numerical applications. ♢ Compared with FORTRAN, Algol 60 provided better ...
  18. [18]
    [PDF] The programming language pascal - Semantic Scholar
    Pascal was developed on the basis of Algol 60 with emphasis placed on keeping the number of fundamental concepts reasonably small, on a simple and ...
  19. [19]
    Recollections about the Development of Pascal
    Pascal was defined in 1970 and, after a slow start, became one of the most widely used languages in introductory programming courses. This article first ...
  20. [20]
    The Development of the C Language - Nokia
    This paper is about the development of the C programming language, the influences on it, and the conditions under which it was created.
  21. [21]
    Timeline of the Ada Programming Language | AdaCore
    The Ada language was designed for developing reliable, safe and secure software. It has been updated several times since its initial inception in the 1980s.
  22. [22]
    Ada Overview - Ada Resource Association
    Ada is a modern programming language designed for large, long-lived applications – and embedded systems in particular – where reliability and efficiency are ...
  23. [23]
    [PDF] 1. Structured Programming and Object-Oriented Programming
    Oct 11, 2015 · It was introduced in 1995 and it's popularity has grown quickly. Javais an object-oriented programming language developed by Sun Microsystems.
  24. [24]
    About Python - Python Institute
    Python was created by Guido van Rossum and first released on February 20, 1991. ... Unlike most languages born in big tech companies, Python was created by Guido ...Missing: structured | Show results with:structured
  25. [25]
    Block Structure
    Mar 29, 2020 · Algol blocks have a declaration section and imperative section. Variables declared in the block are local. Algol blocks can be labeled or unlabeled.Missing: structured | Show results with:structured
  26. [26]
    [PDF] Flow Diagrams, Turing Machines And Languages With Only Two ...
    In this paper, flow diagrams are introduced by the ostensive method; this is done to avoid definitions which certainly would not be of much use. In the first ...
  27. [27]
    [PDF] Structured Programming with go to Statements DONALD E. KNUTH
    A consideration of several different examples sheds new light on the problem of ereat- ing reliable, well-structured programs that behave efficiently.
  28. [28]
    [PDF] An Axiomatic Basis for Computer Programming
    In this paper an attempt is made to explore the logical founda- tions of computer programming by use of techniques which were first applied in the study of ...
  29. [29]
    Structured Programming with go to Statements - ACM Digital Library
    The translation of 'go to' programs to 'while' programs," Proc. IFIP Congress 1971 Vol. 1, North-Holland Publ. Co., Amsterdam, The Netherlands, 1972, 250-255.
  30. [30]
    A Modular curriculum in computer science - UNESCO Digital Library
    UNESCO-IFIP modular curriculum in computer science 272.3 Algorithms and structured programming 2.3 ALGORITHMS AND STRUCTURED PROGRAMMING O b j e c t i v e s ...
  31. [31]
    "Structured Programming in IBM" by Harlan D. Mills
    Jan 25, 1971 · Mills, Harlan D., "Structured Programming in IBM" (1971). The Harlan D. Mills Collection. ... This document is currently not available here.
  32. [32]
    The Post-OOP Paradigm | American Scientist
    The 1960s and '70s saw a crusade to root out "spaghetti code" and replace it with "structured programming. ... Brooks, Jr., who managed the OS/360 software ...
  33. [33]
    [PDF] on structured programming - SpinRoot
    Aug 12, 2011 · ' (Dahl, Dijkstra & Hoare '72) explicitly stated in their preface that the: .. structured programming principles can be equally applied in. ' ...
  34. [34]
    Program Development by Stepwise Refinement, Niklaus Wirth
    Every refinement step implies some design decisions. It is important that these decision be made explicit, and that the programmer be aware of the underlying ...
  35. [35]
    Stepwise Refinement - Computer Science
    Stepwise refinement is a basic technique for low-level design. Invented by Niklaus Wirth in 1971, it may be the oldest systematic approach to software design ...
  36. [36]
    The American side of the development of ALGOL - ACM Digital Library
    New views of programming practice, such as structured programming and formal verification techniques, lean heavily on ALGOL-oriented programming. ALGOL has ...
  37. [37]
    Procedural Languages | Encyclopedia.com
    ALGOL was used more in Europe than in the United States by computer scientists conducing research. ... Pascal タ incorporates the ideas of structured programming ...
  38. [38]
    [PDF] Understanding error rates in software engineering - John Symons
    Sep 29, 2018 · Roughly 100 empirical studies have been published since 1970 on software error rates. Of those studies we chose eleven widely cited studies ...
  39. [39]
    Loop exits and structured programming: reopening the debate
    Loop exits and structured programming: reopening the debate. Author: Eric S. Roberts.
  40. [40]
    [PDF] The Development of the C Language - Nokia
    The Development of the C Language. Dennis M. Ritchie. Bell Labs/Lucent Technologies. Murray Hill, NJ 07974 USA dmr@bell-labs.com. ABSTRACT. The C programming ...
  41. [41]
    Ada '83 Rationale, Sec 14.1: Introduction (to Ch 14
    One family of solutions tends to consider exception handling as a normal programming technique for events that are infrequent, but are not necessarily errors.
  42. [42]
    Structured exception handling - ACM Digital Library
    In this paper, we define what exception conditions are, discuss the requirements exception handling language features must satisfy, survey and analyze ...
  43. [43]
    Chapter 11. Exceptions
    The Java programming language requires that a program contains handlers for checked exceptions which can result from execution of a method or constructor (§8.4.
  44. [44]
    Ada 83 LRM, Sec 11.4: Exception Handling
    When an exception is raised, normal program execution is abandoned and control is transferred to an exception handler. The selection of this handler depends on ...Missing: structured | Show results with:structured
  45. [45]
    Ada 83 LRM, Ch 11: Exceptions
    To raise an exception is to abandon normal program execution so as to draw attention to the fact that the corresponding situation has arisen. Executing some ...
  46. [46]
    Advantages of Exceptions (The Java™ Tutorials > Essential Java ...
    Advantage 1: Separating Error-Handling Code from "Regular" Code · Advantage 2: Propagating Errors Up the Call Stack · Advantage 3: Grouping and Differentiating ...
  47. [47]
    Modern C++ best practices for exceptions and error handling
    Jun 18, 2025 · An exception forces calling code to recognize an error condition and handle it. Unhandled exceptions stop program execution. An exception jumps ...<|separator|>
  48. [48]
    Entry Points in Subroutine Subprograms - Intel
    Specify Component Locations Invoke the Compiler Use the Command Line on Windows Run Fortran Applications from the Command Line File Extensions Use Makefiles ...<|control11|><|separator|>
  49. [49]
    GO TO (Computed) (FORTRAN 77 Language Reference)
    The computed GO TO statement selects one statement label from a list, depending on the value of an integer or real expression, and transfers control to the ...
  50. [50]
    [PDF] Guidelines for Structured Coding. - DTIC
    If the functional blocks of code are identical for more than one case, the appropriate entries in the computed GOTO statement should contain the same number.
  51. [51]
    State Machines for Event-Driven Systems - Barr Group
    May 4, 2016 · State machines are perhaps the most effective method for developing robust event-driven code for embedded systems.
  52. [52]
    Programming embedded systems the easy way – with state machines
    Jan 28, 2020 · This article will give you an introduction into programming with state machines with a focus on graphical design tools.
  53. [53]
    A crash course in UML state machines: Part 1 - Embedded
    Mar 9, 2009 · In this article series, I briefly introduce UML state machines that represent the current state of the art in the long evolution of these techniques.
  54. [54]
    Typed Design Patterns for the Functional Era - ACM Digital Library
    Functional design patterns map domain concepts to functional language features, like the Witness, State Machine, Parallel Lists, and Registry.
  55. [55]
    UML State Machine Diagrams - Overview of Graphical Notation
    State machine diagram is a behavior diagram which shows discrete behavior of a part of designed system through finite state transitions.