Imperative, Functional, and Object-Oriented: Oh My!

So, what is a programming paradigm anyway? And how should I pick the best one?

If you’re grappling with these questions, you’ve come to the right place.

A programming paradigm is a sort of philosophy that will determine how you go about writing code. What is the goal of your program? What does your data look like, and what should your approach be based on that? Paradigms can result in code that is readable, or less prone to errors, or doesn’t mutate your data, or stores your data and methods alongside each other.

Each programming paradigm attempts to address these concerns with its own formula. Some programming languages are even written with a specific paradigm in mind. These paradigms can be valuable tools to have in your back pocket as your goals shift and you move between languages.

I have picked three paradigms to demo: imperative, functional, and object-oriented — the three paradigms I have run into most often in my time programming. Read through the following examples to get a better handle on the world of programming paradigms.

The Problem at Hand

For demonstration purposes, I have made up a problem and written the solution to it in three different ways, each one following a different paradigm. Here it is:

Write a function that takes in a string and returns the sum of the numeric value of each letter in that string.

For example, “hi” is composed of two letters: the 8th letter of the alphabet plus the 9th. When the function is called with “hi” it should return the sum of 8 + 9, so 17.

Feel free to refer back to this problem as you look at the different solutions.

Before we begin the imperative solution, we should make an alphabet constant to hold all of the letters in the alphabet. All three of our solutions are going to make use of this constant. We can use the index of each letter (plus one, since our indices begin at 0 but our letter values begin at 1) to get that letter’s numeric value.

Remember this, because we’ll be coming back to it.

Imperative

Solution

This function takes in a string (‘str’) as its input. It then breaks that string into an array of each of its letters. A counter (‘strValue’) keeps track of the string’s total value; we add to it the value of each letter in our array. Then we return the total value at the end.

If you don’t quite understand all that’s going on inside of our ‘for’ loop, I’ve rewritten the function with each step broken down so as to be more clear.

We begin by grabbing the letter we’re dealing with on that loop. We then can find the index of that letter in the ‘alphabet’ array, add 1 to it to get that letter’s numeric value, and then add it to our ‘strValue’ counter. These four lines of code do the exact same thing as the one line of code in the previous example.

Discussion

Imperative programming is usually what new developers begin writing because it is simple, efficient, and direct. It’s easy for other people to look at your code and immediately understand what’s going on.

But as you can see, it can be pretty lengthy, and isolating a bug can be difficult due to all of the side effects in the code. Furthermore, the order of how the code is written is central. A single mistake can lead to errors.

Functional

Solution

The functional approach looks quite similar to the imperative approach, except that it breaks it up into as many steps as possible, with each step becoming its own function. So, here are our three helper functions.

Note that the ‘findValue’ function makes use of our same ‘alphabet’ constant from before!

Now, we can use these helper functions in our larger function to find the string’s numeric value.

Discussion

Functional programming is my favorite because it results in far fewer bugs. Each step is broken apart, so that the resulting code is cleaner, and potential errors are much easier to track down and fix.

The modularity of functional programming also lets us reuse our smaller, more general units. The same code can solve multiple problems. Also, that code is easier to read and maintain.

Functional programming is perfect for when we are performing many operations on fixed data. However, because functional programming breaks our programs into more steps, it takes up more space than other paradigms. Also, it can be a pain to keep track of the inputs and outputs of each function — something that is extremely important to do.

Object-Oriented

Solution

Object-oriented programming makes use of classes, which store the data and methods of a problem together. The data is stored in the class’ constructor, and then class methods can be written subsequently.

The function doing the heavy lifting here, ‘getStringValue,’ works the exact same way as our imperative solution does. However, since the input ‘str’ and ‘alphabet’ constant are stored in the class’ constructor, they must be referred to using the ‘this’ keyword.

To go about testing this class, first you must make a new instance of the class with a string input. You can then call the class methods on the example, as I have done so below.

Discussion

As you may have guessed from the name, object-oriented programming turns everything into an object containing data and methods. This means that the code is not as concise as that of other paradigms.

However, it is nice in that it doesn’t mutate our data. The original input string is still stored inside of the object, and we could access it if we wanted to. This is not true with the imperative and functional paradigms — with those two, once the function is called, the input in its original form is lost.

Close to functional programming’s opposite, object-oriented programming is perfect for when we are performing few operations on multiple sets of data that share common behavior. Whereas functional programming asks the question of what we need to do, object-oriented programming asks how we will do it.

Summary

Programming paradigms are powerful, exciting, and strange all at once. When I first started coding, I had no way of comprehending that code written in the same language could look so different, much less that each of these ways of writing code came with their own advantages and disadvantages.

Next time you’re solving an algorithm, try doing it with a new paradigm! You may be surprised with how it turns out.