Programming paradigm
2 Main approaches to programming
There are two main approaches to structured programming
Describes the different styles of programming (Source: geeksforgeeks.org)
- Imperative programming – focuses on how to execute, defines control flow as statements that change a program state. It explicitly tells the computer "how" to accomplish it.
- Declarative programming – focuses on what to execute, defines program logic, but not detailed control flow. It describes "what" a program should accomplish.
It’s important to realize that many declarative approaches have some sort of imperative abstraction layer.
So the main differences are that imperative tells you how to do something and declarative tells you what to do.
- Imperative: C, C++, Java
- Declarative: SQL, HTML
- (Can Be) Mix: JavaScript, C#, Python
Structured programming is a programming paradigm that promotes the use of clear, easy-to-follow code structures to enhance code readability and maintainability.
Structured programming discourages the use of unstructured control flow mechanisms like GOTO statements, which can lead to spaghetti code and make code difficult to understand and modify. By organizing code into coherent blocks and enforcing a top-down design approach, structured programming helps developers create robust and efficient programs while improving debugging and maintenance capabilities.
Imperative programming and Declarative programming are both the sub catagories of Structured programming
Comparsion
Analogy
I’m going to ask you a question. I want you to think of both an imperative response and a declarative response.
“I’m right next to Wal-Mart. How do I get to your house from here?”
Imperative response: Go out of the north exit of the parking lot and take a left. Get on I-15 North until you get to the 12th street exit. Take a right off the exit like you’re going to Ikea. Go straight and take a right at the first light. Continue through the next light then take your next left. My house is #298.
A declarative response: My address is 298 West Immutable Alley, Eden, Utah 84310
Code example example
This seciont is mostly copied from Imperative vs Declarative Programming. I found this example is very clean and easy to understand.
For the full explaination of the example, please refer to the link.
function double(arr) {
let results = [];
for (let i = 0; i < arr.length; i++) {
results.push(arr[i] * 2);
}
return results;
}
function add(arr) {
let result = 0;
for (let i = 0; i < arr.length; i++) {
result += arr[i];
}
return result;
}
$("#btn").click(function () {
$(this).toggleClass("highlight");
$(this).text() === "Add Highlight"
? $(this).text("Remove Highlight")
: $(this).text("Add Highlight");
});
By examining what all three of these imperative examples have in common, we’ll be able to better identify what actually makes them imperative.
- The most obvious commonality is that they’re describing HOW to do something. In each example, we’re either explicitly iterating over an array or explicitly laying out steps for how to implement the functionality we want.
- This one might not be as obvious if you’re not used to thinking in the declarative or even more specifically functional way. In each example, we’re mutating some piece of state (If you’re unfamiliar with the term state, it’s basically information about something held in memory — which should sound a lot like variables). In the first two examples we create a variable called results, and then we continually modify it. In the third example, we don’t have any variables, but we still have state living in the DOM itself — we then modify that state in the DOM.
- This one is a bit subjective, but to me, the code above isn’t very readable. I can’t just glance at the code and understand what’s going on. My brain needs to step through the code just as an interpreter would while also taking into account the context in which the code lives(another negativity of mutable data).
Let’s now take a look at some declarative examples. The goal is to fix all the problems from above. So each example needs to describe WHAT is happening, can’t mutate state, and should be readable at a glance.
function double(arr) {
return arr.map((item) => item * 2);
}
function add(arr) {
return arr.reduce((prev, current) => prev + current, 0);
}
<Btn
onToggleHighlight={this.handleToggleHighlight}
highlight={this.state.highlight}>
{this.state.buttonText}
</Btn>
Notice that in the first two examples we’re leveraging JavaScript’s built-in map and reduce methods. This goes back to what we’ve been talking about over and over in this article, the most declarative solutions are an abstraction over some imperative implementation.
In every example we’re describing WHAT we want to happen rather than HOW (we don’t know HOW map and reduce are implemented, we also probably don’t care). We’re not mutating any state. All of the mutations are abstracted inside of map and reduce. It’s also more readable (once you get used to map and reduce, of course).
Now, what about the last example? Well, I cheated a little bit and am using React — but note that all three imperative mistakes are still fixed. The real beauty of React is that you can create these declarative user interfaces. By looking at our Btn component, I’m able to quickly understand what the UI is going to look like. Another benefit is instead of state living in the DOM, it lives in the React component itself.
Another less-spoken-of benefit to declarative code is that your program can be context-independent. This means that because your code is concerned with what the ultimate goal is— rather than the steps it takes to accomplish that goal — the same code can be used in different programs, and work just fine.
Look at all three of our examples above. We can consume both functions and component in any program we want. They’re program agnostic. This is hard to do with imperative code because often times, by definition, imperative code relies on the context of the current state.
Imperative programming (How you want it done)
// average of five number in C
int marks[5] = { 12, 32, 45, 13, 19 } int sum = 0;
float average = 0.0;
for (int i = 0; i < 5; i++) {
sum = sum + marks[i];
}
average = sum / 5;
Procedural programming
- It is a structured programming which specifies the steps a program must take to reach a desired state.
- A procedure is basically a function that DOESN'T return any value, and ACHIEVES some sort of side effect.
const list = [1,2,3,4,5,6];
const sum = 0;
for(let i = 0; i < list.length; i++){
sum += list[i]
}
Object-oriented programming (OOP)
It organizes programs as objects: data structures consisting of datafields and methods together with their interactions.
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.
Describes the key concepts of object-oriented programming (Source: javatpoint.com)
Declarative programming (What you want to be done)
SELECT * FROM Users WHERE Country=’Mexico’;
<article>
<header>
<h1>Declarative Programming</h1>
<p>Sprinkle Declarative in your verbiage to sound smart</p>
</header>
</article>
By glancing at both examples, you have a clear understanding of what is going on. They’re both declarative. They’re concerned with WHAT you want to be done, rather than HOW you want it done.
You’re describing what you’re trying to achieve, without instructing how to do it. The implementation of selecting all of the users who live in Mexico has been abstracted from you. You’re not concerned with how the web browser is parsing your article and displaying it to the screen. Your WHAT is Mexican users or a new header and paragraph on your website.
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.
- It treats programs as evaluating mathematical functions and avoids state and mutable data.
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
In computer science, an operation, function or expression is said to have a side effect if it modifies some state variable value(s) outside its local environment, that is to say has an observable effect besides returning a value (the main effect) to the invoker of the operation. State data updated "outside" of the operation may be maintained "inside" a stateful object or a wider stateful system within which the operation is performed wiki
- 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.
Take for example creating a
List
with 3 items and storing it in a variablemy_list
. Ifmy_list
is immutable, you wouldn't be able to change the individual items. You would have to setmy_list
to anew List
if you'd like to use different values. - 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 are treated like an object, which means it can be passed to other functions as arguments.
- Higher-Order Functions — Higher-Order functions are functions that accept at least one first class function as a parameter and returns a function as its result.
// Generating a Fibonnaci sequence
fib(n)
if (n <= 1)
return 1;
else
return fib(n - 1) + fib(n - 2);
Reactive programming
It 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). For each stream, you have a subscriber that responds accordingly.
Use cases:
- Availability notifications
- Ingested messages
- Click events
- HTTP requests
Source: Reactive Programming In JavaScript