The Simple Guide to Programming Paradigms
Tamerlan Gudabayev
Posted on July 26, 2021
I've published over 30 articles this past year, with that comes a lot of research and I've seen so many different programming paradigms that I just have to write about it.
But before we begin, we first got to know what is a programming paradigm.
Table of Contents
Programming Paradigms
As developers our number one enemy is complexity.
I'm sure you've heard the term, "If I had more time, I would've made the program simpler".
Because simpler code is more maintainable and can be easily debugged.
In a nutshell:
Complexity is the enemy
To battle complexity, software developers have created different programming paradigms or styles of programming, similar to martial arts. It's not bound to a specific programming language, but some languages are more suited to one style.
Let's go over the history of these paradigms.
The Dark Ages
The earliest known programming paradigm was called non-structured. It was barbaric due to the use of goto statements to literally jump to different areas of the code.
It got the job done, but at what cost?
Unreadable or spaghetti code.
Many people complained about the brutality of non-structured programming, it was horrible to maintain and debug.
Until one day, a man by the name of Edsger W. Dijkstra advocated against using goto or equivalent.
Thus creating his own style of programming called structured programming and ending the dark ages of non-structured.
Structured Programming
The school of structured programming brought many successes.
Computer programs had more clarity, quality, and were made faster than ever.
Structured programming advocated the use of structured control flow such as:
-
Conditionals —
if/then/else
-
Repetition —
while/for
- Block Structures
- Functions
They also completely rejected the use of dark arts, such as goto or its equivalent.
Structured programming was the default, and many new programming languages were created with structured programming in mind.
Eventually, structured programming advanced so much that it was too divided into two new styles.
Imperative Programming
The first of these new styles was imperative programming.
Imperative programming is a programming paradigm that uses statements to change the programs state. It focuses on the HOW by showing you the solution step by step.
For example, let's say we were tasked to return even numbers from a list of integers.
Imperatively we would solve it like this:
const list = [1,2,3,4,5,6];
const result = [];
for(let i = 0; i < list.length; i++){
if(list[i] % 2 == 0){
result[] = list[i]
}
}
Here we know exactly what's happening, we can simply follow the code, and see how the solution works.
Within imperative programming, there are also another two inner-schools.
Procedural Programming
Procedural programming is a subset of imperative programming where we split the step by step instructions into procedures.
But what is a procedure?
A procedure is basically a function that DOESN'T return any value, and ACHIEVES some sort of side effect.
A good example would be the classic loop in most programming languages.
const list = [1,2,3,4,5,6];
const sum = 0;
for(let i = 0; i < list.length; i++){
sum += list[i]
}
It's essentially a function that doesn't return anything but causes side effects.
Benefits of Procedural Programming:
- Excellent for general-purpose programming
- Because of the simplicity of the code, it's easier to implement compilers and interpreters
- Simplicity
- Ability to be highly modular
- The memory requirement is slow, making it fast and efficient
Languages that support Procedural Programming:
- C
- C++
- Java
- Javascript
- Python
Object-Oriented Programming
Object-Orientated Programming is a subset of imperative programming where you structure your code in objects that can hold data (in form of fields) and code (in form of methods).
Object-Oriented Programming is by far one of the most popular and widely used programming paradigms in our times.
There are four main principles in Object Orientated Programming:
- Encapsulation - Binds data and it's related methods together within a class. It also protects the data by making fields private and giving access to them only through their related methods.
- Abstraction - It's the concept of object-oriented programming that "shows" only essential attributes and "hides" unnecessary information.
- Inheritance - It's the mechanism of basing an object or class upon another object or class, retaining similar implementation.
- Polymorphism - It's the ability of an object to take on many forms.
I have another article, with an in-depth explanation for each of these principles.
You can read it here.
OOP Principles For Dummies
Tamerlan Gudabayev ・ Mar 21 '21
Benefits of Object Orientated Programming:
- Reusability due to inheritance
- Flexibility due to Polymorphism
- Security due to Encapsulation and Abstraction
- Lower costs due to reusability
Languages that support Object-Oriented Programming:
- Java
- C++
- Python
- PHP
Declarative Programming
On the other hand of the spectrum we have declarative programming, it also comes from structured programming but unlike imperative programming where it focuses on the HOW, declarative programming focuses on the WHAT.
An example of a declarative programming language would be SQL (Structured Query Language).
So let's say for example you want to get all rows from a table called users
SELECT * FROM users
You don't really care how SELECT
works, you simply want to get all users.
Similar to imperative programming, declarative programming also has four inner schools.
Logic Programming
Logic Programming is a programming paradigm based on formal logic. Meaning that you have a bunch of facts/statements, and you get new statements that comply with the original facts.
A classical example would be:
- Socrates is a Man
- All Men Are Mortal
From these two statements, we can conclude that Socrates is also mortal.
But how is this expressed in code?
Take a look at an example made in Prolog:
man(Socrates).
mortal(X) :- man(X).
?- mortal(Socrates).
Let's break this down:
- The first line expresses that Socrates is a man.
- The second line says "X is mortal if X is a man".
- The third line is our question that says "Is Socrates mortal?" which will return
yes
.
Benefits of Logic Programming:
- Simple to write code
- Easy to debug
- Fast development
- Ideal for expressing complex ideas and algorithms
- Allows data to be represented both extensionally and intentionally
Languages that support Logic Programming:
- Prolog
- Absys
- ALF (algebraic logic functional programming language)
- Alice
- Ciao
Functional Programming
Functional Programming is by far the most used declarative programming paradigm, the basic premise is that programs are constructed by applying and composing functions.
Let's take a look at this example:
// Generating a Fibonnaci sequence
fib(n)
if (n <= 1)
return 1;
else
return fib(n - 1) + fib(n - 2);
Functional Programming has to follow a set of principles:
- Pure Functions — All functions must be pure, meaning that it should have no side effects and it should be deterministic, returns the same result if given the same arguments
- Immutability — When data is immutable, its state cannot change after it’s created. If you want to change an immutable object, you can’t. Instead, you create a new object with a new value.
- Referential Transparency — Basically because we got pure functions and immutability, we can replace all function calls with their underlying return values and the program would still work.
- Functions as First-Class Entities — It means that functions can be passed to other functions as arguments.
- Higher-Order Functions — Higher-Order functions are basically functions that accept other functions as arguments and returns a function as its result.
Benefits of Functional Programming:
- It helps us to solve problems effectively in a simpler way.
- Improves modularity.
- Allows us to implement lambda calculus to solve complex problems.
- Reduces complex problems into simple pieces.
- Debugging is easy.
Languages that support Functional Programming:
- Haskell
- JavaScript
- Scala
- Erlang
- Lisp
- Clojure
Reactive Programming
Reactive programming is a programming paradigm that is concerned with data streams, and how it reacts to it.
For example, you can have multiple streams (also called observers)
- Click events
- HTTP requests
- Ingested messages
- Availability notifications
For each stream, you have a subscriber that responds accordingly.
Benefits of Reactive Programming:
- Simple to do asynchronous work
- Avoid “callback hell”
- Simple to compose streams of data
- Simplifies complex threading
- Cleaner and maintainable code
- Easy to implement back-pressure
Languages that support Reactive Programming:
- Scala
- Haskell
- Elm
- Javascript
Conclusion
There aren't all the programming paradigms available, there are many others I couldn't cover in this article. But I covered the main ones at the least, and I hope you have a better understanding of each.
Thanks for reading, and don't forget to follow me on Twitter.
Posted on July 26, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.