Functional Programming

Projected Time

About 2 - 2.5 hours

Prerequisites

Motivation

Functional Programming (FP) is a programming paradigm that’s different from object-oriented programming. Functional programming is all about separating data from behavior so that software is more predictable, more robust, and easier to test. Certain tools become readily available with functional programming because functions can be used as data, which means they can be passed around as parameters and used as inputs into other functions. This can make the code more concise and easier to read.

Which companies use Functional Programming?

(futurelearn.com)

Objectives

Participants will be able to learn the basics of functional programming in JavaScript.

Specific Things to Learn

Materials

Lesson

Tweet about functional programming

Here is a list of tools that become available with functional programming. These functions are commonly used on containers, such as an array, to apply another function across all elements in that container.

Part I. Map

The purpose of map is to process every element of an array in the exact same way. When you call map on an array, it executes that callback on every element within it, returning a new array with all of the values that the callback returned. Example: an array of integers, add ‘3’ to every integer

    const intArray = [1, 2, 3]

    function add3(value) {
      return value + 3;
    }

    const result = intArray.map(add3) // result is [4, 5, 6]

Part II. Filter

The purpose of the filter is to return a specified subset of the original array elements. When you call filter on an array and a function, it uses the function to check to see if the elements in the array meet a certain condition. If it does meet the condition, it keeps it in the array; if it does not meet the condition, it filters it out of the array. Example: Let’s say that you have an array of restaurants, and you want to know what your options are for only restaurants that are open at 7 am. You have a class called Restaurant, which has a property openingTime.

    const validRestaurants = allRestaurants.filter(restaurant => restaurant.openingTime <= 7)

Part III. Reduce

The purpose of reduce is to process elements of an array in a way that every element will be incorporated into the final solution. When you call reduce on an array and a function, it applies the function to every element of the array, while keeping track of a previous value. Example: You are going to binge-watch Season 2 of “Stranger Things”, and you want to know how long it will take. You have a class called Episode, which has duration as the value, and you have all of the episodes of Stranger Things stored in an array.

    const seasonTwoEpisodes = allEspisodes.filter((episode) => episode.season == 1)

    function addDuration(episode1, episode2) {
      return episode1.duration + episode2.duration;
    }

    const total = seasonTwoEpisodes.reduce(addDuration, 0)

Part IV. Mutation

Something you may have noticed is that when the new values were calculated from the original arrays, the old array values stayed unchanged. Therefore, they are considered to be “non-mutating”. Let’s look back at the example in Part I. Example: an array of integers, add 3 to every integer

    const intArray = [1, 2, 3]

    function add3(value) {
      return value + 3;
    }

    const result = intArray.map(add3) // result is [4, 5, 6]

If you inspect intArray, the values are still: [1, 2, 3]. There are many functions that have mutating vs. non-mutating behavior. For example, splice is a mutating way to replace values, as opposed to map. A good article that explains different mutating vs. non-mutating functions can be found here

Generally, according to the functional programming paradigm, it’s better to avoid mutation of data. This will help keep code behaving more robustly and predictably. In fact, some programming languages are specially crafted for, or influenced by Functional Programming, some examples of Functional Programming Languages are:

JavaScript is not a purely functional language, but has some methods like map, reduce, and filter are functional in nature. Purely functional languages are specialized languages and have often have limited applications.

Why is avoiding mutation a good idea?

You may wonder why you would want to avoid mutation. Let’s say we defined a method, add3(intArray), that would update an array of integers whenever we called it instead of returning a new array. We would say that such a method has a “side effect” of changing the array (intArray). Now, what if we had to call add3 from two different parts of our application? We would have to start worrying about how many times add3(intArray) was called because every time we call it, intArray would change.

This might not be a problem in a small application, but as the application grows over time, we may get unexpected results. As more people start working on the project, they may not be aware that each time they call add3(intArray) the intArray would change. This could quickly break an application in weird and hard-to-debug ways. For that reason, developers tend to prefer avoiding side-effects. Using a method like map, which returns a new array and leaves intArray as it is, is an easy way to avoid these types of mistakes.

Independent Practice

Extensions

Supplemental Materials