Functional Programming vs Imperative Programming

Understand the changing programming paradigm and how it has led to functional programming.

A programming paradigm consists of the rules and design principles for building software. Paradigm changes mean that something in current software development strategies isn’t meeting modern demands. For example, we may have multiple tasks and huge amounts of data need to be processed quickly and reliably. The CPU isn’t getting faster—we can’t just write code and hope it will be faster with a new CPU launch. Instead, we have multiple cores or even machines to process stuff. We need to write code that takes advantage of concurrency and parallelism. Unfortunately, it’s hard to get it right when working in imperative and object-oriented languages. This is just one example of where these common approaches can fail. Let’s take a closer look at the limitations of imperative programming.

The limitations of imperative languages

Imperative languages have shared mutating values. This means that many parts of the program can reference the same value, and it can change. Mutating values can be dangerous for concurrency; we can easily introduce hard-to-detect bugs. For example, take a look at this script in Ruby:

list = [1, 2, 3, 4]
list.pop
# => 4
# => [1, 2, 3]
list.push(1)
# => [1, 2, 3, 1]
puts list.inspect
# => [1, 2, 3, 1]

In this chapter, we’ll see more code examples like the one above. Don’t worry about the syntax or how the language works. The focus is on the concepts.

Here, we can mutate the data by adding or removing elements. Now imagine multiple parts of an application running in parallel and having access to the list simultaneously. What could happen if, in the middle of some operation, the value changes because of another process?

It’s hard to predict and can cause headaches for developers. That’s why many features and libraries in these imperative languages offer mechanisms to help us lock and synchronize the changes. However, that’s not the only way. Functional programming offers a better alternative.

Moving to functional programming

In this course, we’ll learn about anonymous functions, free and bound variables, and functions as first-class citizens. Each of these come from the lambda calculus computation model, created by Alonzo Church in the 1930s.

Lambda calculus is the smallest universal language that can simulate any real computation that’s Turing complete.

If we see a programming language with lambdas, we can be sure that Church’s model has influenced it.

With a functional language like Elixir, we’ll make better use of our CPU multi-cores, writing shorter and more explicit code. When we apply the functional paradigm in a functional language, we write code that lives harmoniously with the language. But it doesn’t come for free. We must understand and follow these core principles: immutability, functions, and declarative code.

This chapter will examine these principles in detail and see how the functional foundation is better prepared for modern demands.