Imperative vs Declarative programming – What do they actually mean?

Imperative vs Declarative programming – What do they actually mean?

Subscribe to my newsletter and never miss my upcoming articles

I am not sure about you, but I have personally battled with fully wrapping my head around the concept of declarative and imperative programming and the differences thereof. The textbook definitions and a lot of the definitions you search on Google are often either very complex and difficult to understand, say a lot but don't actually give you clarity at all or are really verbose with no clear meaning.

Here are a few of the definitions I have come across that attempt to bring across the meaning of imperative and declarative programming:

"Declarative Programming is programming with declarations, i.e., declarative sentences."

"The declarative property is where there can exist only one possible set of statements that can express each specific modular semantic. The imperative property is the dual, where semantics are inconsistent under composition and/or can be expressed with variations of sets of statements."

"Declarative languages contrast with imperative languages which specify explicit manipulation of the computer’s internal state; or procedural languages which specify an explicit sequence of steps to follow."

"In computer science, declarative programming is a programming paradigm that expresses the logic of a computation without describing its control flow."

I personally do not have a background in Computer Science and so a lot of the above definitions did not give me any clarity on what Imperative and Declarative programming actually is. Now, I am not saying that these definitions are incorrect or that they do not help, but in my personal capacity, I found it rather difficult to wrap my head around these them.

So, this article is for those who were just like me and still haven't had that "AHA!" moment.

Let's get to it shall we?

The one definition that I came across stated:

Imperative programming is like how you do something, and declarative programming is more like what you do.

This was probably the closest I got to a definition that almost made sense. The issue is that this definition makes far more sense when you actually know what imperative and declarative programming actually is.

What do "imperative" and "declarative" actually mean?

So what I am going to do is start by removing the programming aspect from what we are trying to understand and look at both "imperative" and "declarative" from a language perspective. I am going to paint a quick scenario to help you understand these two terms.

So, you are casually walking in the city and a kind stranger stops you and asks you for directions to the nearest place to buy Tacos.

The imperative approach would be to give him the directions relative to where you are now. It would look a little something like this: "you walk down the street and take your first left. When you get to the traffic light, cross the street and walk down three blocks. You will then find on your left a food market. Once you enter the market, walk all the way to the end and you will find the Taco store."

A declarative approach would look a little something like this: "You can find the Taco store at the food market, the address is 123 Taco Street, Johannesburg, Gauteng, 2009."

Now what is the glaring difference between the two? The first approach was a step by step process on how to get to the store and the second approach was a way to get to the store without describing step by step how to get there.

So the imperative approach (the HOW) explicitly lays out the steps to achieve what you want. The declarative (the WHAT) describes what you want to achieve without actually instructing how to do it.

One important thing to take note of in the above example is that with the declarative approach, knowing the address assumes that you have some form of navigation system that knows the imperative steps of how to get to the food market. The underlying concept to remember from this is that most, if not all declarative approaches have some form of imperative abstraction layer. Declarative solutions are an abstraction over some imperative implementation.

Let's look at some code

Enough with all the analogies, let's look at some code and see how these concepts apply when it comes to writing code.

Imperative programming

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
}

Over here we have two functions. The double function takes an array as a parameter, loops through that array and for every element in that array, doubles it and pushes it to the results array and then returns the results array. The add array just sums all the elements in the array and returns the result.

3 Characteristics of imperative code

Now, there are three key characteristics we can observe in the above code.

  1. The above code explicitly describes HOW the function works. You iterate over the code and either add or double. Imperative code describes how to do something or explicitly lays out the steps on how to achieve the functionality we desire.
  2. In the above functions we are mutating state. We create a results variable and mutate it throughout the function. Imperative code often mutates state.
  3. You probably cannot quickly glance at the above code and figure out what is actually going on. Imperative code is often not very readable.

Declarative Programming

So, what would the declarative implementation of the previous code look like? I am sure glad you asked!

function double (arr) {
  return arr.map((item) => item * 2)
}

function add (arr) {
  return arr.reduce((prev, current) => prev + current, 0)
}

You will notice in the above code that I have used some built-in JavaScript methods, map and reduce. Remember when I said earlier that declarative solutions are really just an abstraction over some imperative implementation? I hope that statement is starting to make sense to you in light of the examples I have explained above.

In the above declarative implementation, we are describing what we want to happen and not so much how we want it to happen. If you look at the code, we do not know how map and reduce work, we know that there is some imperative implementation under the hood, but we do not know how the methods work and quite frankly I do not think we care or need to care about how they work either. In the above declarative code, you will notice that we are not mutating state either – all of the mutations are abstracted inside of the map and reduce methods.

Final Thoughts

There you have it! Imperative and declarative programming as best I could explain it. What I personally really love about declarative programming is that fact that your code is program agnostic. When you code declarative code, your code is concerned about what the ultimate goal is rather than the steps required to accomplish that ultimate goal and as such, you can use that code in various different programs and it will function just fine.

I hope this article will lead you to the lovely "AHA!" moment. Till next time 🚀.

 
Share this