JavaScript Overview — Functional Programming (Immutability, Side Effects, Pure Functions, HOFs)

Vlad Antsitovich
5 min readMar 4, 2022

--

In this article, we will cover the functional programming coding principles. But first, we will define Object-oriented programming and functional programming, discuss the differences between the two, and outline the reasons why we use functional programming.

OOP and FP

Object-Oriented Programming (OOP) is a programming paradigm based on objects and statements. Objects are programming abstractions used to organize pieces of an application. In OOP, objects usually contain and store data in attributes, have procedures they can run in methods, and have some notion of this or self, a way for the object to reference itself. Generally, objects come in the form of classes. A class can be thought of as the definition of an object, with its attributes, methods, and this scope. An object is the instantiation of a class. In OOP, statements are instruction-driven code.

Functional Programming (FP) is a programming paradigm based on expressions and declarations instead of objects and statements. In short, this means that FP relies on functions instead of objects to organize code and build applications. Functional Programming is thought to have originated from lambda calculus, which was created in the 1930s. Functional Programming relies on seven key concepts: declarative functions, pure functions, higher order functions, shared state, immutability, side effects, and function composition. Each of these concepts will be covered in a subsequent topic in this article.

Why Functional Programming?

Functional Programming is designed to be more concise, predictable, and testable. These benefits, however, can result in FP code being denser than other coding paradigms.

Declarative vs. Imperative programming

There are two general ways to think about writing code: Declarative and Imperative. Code written in the Functional Programming paradigm should be declarative.

  • Declarative — specify what to do, not how to do it
<section>
<h1>Hello</h1>
</section>
  • Imperative — specify both what and how

int x; — what (declarative); x=x+1; — how

These definitions are difficult to understand if you have never studied declarative and imperative code before. Declarative code is generally used with Functional Programming and imperative code is generally used with Object-Oriented Programming. There is no “right answer” when deciding which coding style to use; they both have their trade-offs. However, declarative code fits the Functional Programming paradigm better than imperative.

Functional Programming concepts

Immutability

The single most important aspect of FP is immutability. Generally speaking, this means a lack of change. Something is considered immutable if we cannot modify it in some way. In functional programming, this means a few things. Once a variable is set, its value cannot be changed. If x = 3 at the beginning of a program, it has that value for the remainder of the program. Does that mean that if a program is written in a functional style, and a person’s age changes, this change cannot be modeled? Of course not. That would be a disaster for functional programming. There are techniques like copying that allow us to efficiently, manipulate our code, without ever mutating state.

Lots of mutable state in a program is a source of many bugs. It’s simply not easy to keep track of all the changing values.

When something is “Immutable”, it cannot be modified after it is created.

Side Effects

A pure function must have no side effects. This simply means that a pure function cannot modify any objects or values passed in by reference. If your function needs to update or modify value internally, we must first create a copy of the value.

Pure Functions

A pure function can be defined as a function that does not have any effect on or make use of any state outside of the function. A function must meet three key criteria to be considered pure:

  • A function must always return the same output when given the same inputs.
  • A function must have no side effects.
  • A function must have referential transparency. A referentially transparent function is one which only depends on its input.

A pure function is a function that is deterministic and has no side effects.

A function is deterministic if, given the same input, it returns the same output.

Shared State (Stateless)

A shared state is any variable, object, or memory space that exists in a shared scope. In FP shared state should be avoided. A shared state prevents a function from being pure.

A shared state can make it difficult to understand a function. It slows down development because we must take more time to understand the functions that rely on them, then it’s likely we will not write code that is efficient and bug-free.

Higher-Order Functions

Higher-Order Function (HOF) is a function that either takes another function in as an input argument or returns another function as the return value.

HOFs are very important for abstraction. Abstraction is a way to hide the internal workings or details of a procedure.

Higher-order functions can be very useful for creating functional utilities or reducing complexity.

Function Composition

In Functional Programming, Composition takes the place of inheritance in OOP.

Function composition is a way of combining pure functions to build more complicated ones. Like the usual composition of functions in mathematics, the result of one function is passed as the argument of the next, and the result of the last one is the result of the whole.

For example, if we want to find the sine of 30 degrees (remember sine uses radians) we could “compose” these two items into a single line: result = sin( degrees_to_radians( 30 ) ). This is the same as in math where we often see f(g(x)).

Programming is the art and science and engineering of managing complexity. Functional programming brings with it tools we can use in an attempt to restrain and control this complexity.

Recursions

The process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called as recursive function.

Example of recursion where we reverse an array:

const reverse = ([x, …rest]) => x !== undefined ? […reverse(rest), x] : [];

Loops are Imperative. Recursions are Declarative.

Sources

--

--

No responses yet