1. Overview

In this tutorial, we’ll dive into the procedural programming paradigm. We’ll learn about its key characteristics and how it’s different from other paradigms.

2. Procedural Programming

Procedural programming is an imperative programming paradigm. In procedural programming, we organize sets of statements in procedures run sequentially. Thereby, the behavior of the programs is defined as a set of sequential operations. A procedure, a function, a method, or a subroutine is a callable unit. These procedures are called from other procedures, which creates a hierarchy of calls. Procedural programming is the most natural design approach in software engineering. In the next section, we’ll go through the key characteristics of procedural programming.

2.1. Modularity

In procedural programming, modularity is achieved by breaking down the program into smaller independent sections. These sections or modules are dedicated to performing a single function. Thereby, making it easier to manage the overall design of the program. In addition, it also makes the program more readable and easier to maintain. Furthermore, a modular program is easier to debug. For instance, if we’re developing a huge enterprise software and there is an error in the login section of the program, then we’ll be looking specifically at the authentication module for that error. Moreover, it’s common for the modules to be independent or decoupled. It makes testing and reusing the independent modules easier throughout the project. Usually, we follow a top-down approach to achieve modularity, which involves several steps:

  • Begin with the high-level design that outlines the general concepts and functionality of the system
  • Decompose the design into smaller parts
  • Create independent modules that focus on doing one thing
  • Create a central module that integrates the other modules

2.2. Procedural Abstraction

In procedural programming, we also heavily use procedural abstraction, which is the process of encapsulating a sequence of operations into a function that can be reused. This allows us to hide the details of the operations from the rest of the program. For instance, if we need to calculate the area of a circle, we can define a procedure and give it a meaningful name:

FUNCTION circleArea(radius)
    IF radius < 0 THEN
       THROW ERROR "Radius cannot be negative"
    END IF
    RETURN PI * radius * radius
END FUNCTION

The calling code only needs to know the procedure’s name and parameters; it doesn’t need to know its implementation details.

2.3. Variable Scoping

Variables and constants can be defined either globally or locally inside a procedure. However, it’s highly recommended to avoid the use of global variables whenever possible. It makes the code easier to understand and reduces the likelihood of accidental mutation.

2.4. Sharing

Due to the modular nature of a procedural program, it’s typical to share data among the different modules. The data can be variables, constants, and callable units. The most common approach to sharing data is the use of libraries. In a library, we define specific data and operations that can be reused across different programs.

2.5. Sequential Execution

In procedural programming, it’s ordinary to think of a program as a sequence of operations that runs one after another. During the high-level design, we conceptualize the program’s steps to solve a specific problem. Thus, the whole program flow is quite predictable. For instance, if we want to write a program that finds whether a given number is even, we write the solution as a sequence of operations:

  1. Take the user input
  2. Continue if the input is a valid number or print the error and quit
  3. Call the function that checks whether the number is even
  4. Evaluate the return value
  5. Print the result

In this solution, the checker function will contain its own set of sequential instructions.

3. Procedural Programming vs. Other Paradigms

Object-oriented programming (OOP) and procedural programming are both classified as imperative programming. In OOP, we break down the program in terms of objects that contain their behavior and characteristics. We communicate and modify the state of the objects through messages. In contrast, procedural programming relies on dividing the program into variables, data structure, and sub-routines. On the other hand, functional programming is also classified as imperative programming. However, it focuses on transforming the data from one state to another through the use of high-order functions with no changes to the original data. Conversely, procedural programming relies heavily on the mutability of data.

4. Procedural Languages

There are a lot of programming languages that can be used as procedural programming languages. However, most of these languages are based on imperative programming that also supports procedural programming as a subset:

  • FORTRAN
  • ALGOL
  • C
  • COBOL
  • Rust
  • Pascal

Some of these programming languages are multi-paradigm. The idea is that most languages support multiple programming paradigms to some extent, which offers flexibility for developers.

5. Conclusion

In this article, we discuss the procedural programming paradigm and its key characteristics. Then, we covered how procedural programming is different from object-oriented programming. Finally, we outlined several widely used procedural programming languages.