In your coding journey, you may have heard rumblings about Functional Languages. While functional programming is not particularly marketable, and shouldn’t be your first language, it’s still pretty interesting. Understanding the concepts behind functional programming languages can help your overall programmatic understanding. This is meant to be a very basic introduction to some of the ideas behind functional programming and why you may find them beneficial.
The best way to describe functional programming is to contrast it with more traditional object-oriented programming. Often thought of as a more esoteric programming paradigm, functional programming languages such as Haskell and Clojure are distinct from more traditional object-oriented languages such as Ruby, Python, C++ and Java. While there are some “functional-only” languages, most modern object-oriented languages support both functional and object-oriented styles.
In declarative (functional) programming, functions can be treated as first class objects. This means that functions can be passed around as values, functions can pass into other functions as parameters, and one function can return another function. Functions are composed of other functions so that you can transform values without describing the internal steps involved in transforming the values. Contrast this with imperative (object-oriented) programming, where you describe the step-by-step processes needed to modify variables and get your answer.
Below is a simple example of using JavaScript in an object-oriented imperative style and then in a functional declarative style.
//Problem -- I want to take a list of "User Objects"
and turn it into a simple list of first names
//Sample data
var people =
[{ firstName: "Charles",
lastName: "Xavier",
superheroName: "Professor X"
},
{ firstName: "Ororo",
lastName: "Monroe",
superheroName: "Storm"
}];
In the above object-oriented example, we have to tell the computer to loop over an array, index into the array, get the first name, add that name on to another array, and repeat until there are no more people left. Finally, we can return the name array that has been mutated to have the values we want.
In contrast, here is a solution in the functional style:
//The Functional Approach
function getFirstNames(people) {
//return a transformation of the people list
return people.map(getFirstName)
}
function getFirstName(person) {
//another function that takes a person and returns their name
return person.firstName;
}
Here in the functional solution, we are saying return the same list of people, but only after transforming it with the function “getFirstName.” The “getFirstName” function just takes a person and returns their firstName. This example is using what is known as a map, a staple of functional programming. The map function takes another function as an argument and applies that function to each element in a list. It then returns the same list of elements, however each element has been transformed by the function we passed to map. Here, we just transformed a list of people into a list of those peoples’ firstNames. While this may seem a little weird and confusing at first, many people find this method much more expressive and clear than an object-oriented approach. However, it is important to note that both approaches return the same answer. One is not necessarily better than the other, they are simply two different ways to approach the problem.
Your programs can become more straightforward, understandable, easier to test, and easier to maintain.
One of the main strengths of functional programming is that it makes code easier to reason about. One way this happens is that functional programming languages either encourage or enforce ”pure functions”. This just means that a function will not have any side effects and will not modify an outside object or change state. With pure functions, given the same input you will get the same output every time. This is not always true for object-oriented style functions where your object might be holding on to some state that could change the output of a function. Once you get the hang of working with pure functions, it can become much simpler and easier to reason. Your programs can become more straightforward, understandable, easier to test, and easier to maintain.
One great example of how functional concepts can be used beneficially is seen in the React framework for front-end JavaScript development. Making complex front-end JavaScript applications is difficult. These applications often have a tendency to turn into giant balls of spaghetti code over time. This looks exactly like it sounds — a tangled mess of inter-dependant code. If each function can mutate the global state being used by other functions, it is hard to reason about what each function does. To understand any specific piece of code, you would need to know what every other piece of the code does. If this sounds difficult, it’s because it is!
In an attempt to fix this, React.js applied a functional paradigm to this problem, specifically the idea of one-way data flow and pure functions. As opposed to normal two-way data flow between JavaScript and all of its interdependencies, React makes you manage the state of your application in once place. Then, you can define render functions that transform the state into HTML. When a user interacts with your application, those events move in a well defined loop that modifies the one global state. At that point the render function will rerun and output new HTML, leading to very predictable applications. React is known for being fast, mostly due to optimizations made possible by this predictability. This functional-style framework helped developers clean up their JavaScript and reduce many of its inefficiencies. It is also a great example of how functional programming ideas can help us write better programs in any language.
Functional programming is not a programming cure-all.
Functional programming is not a programming cure-all. Working with functional languages can sometimes be more complicated, especially when programmers are used to object-oriented or procedural programming. It can be difficult to understand a complicated functional program that uses many higher order functions if you aren’t very familiar with those concepts. Functional languages do not work well for certain types of projects, such as writing device drivers or complex video games. A video game, for example, needs to track the state of an entire game world as a player progresses. Because there is so much state (player health, obstacles, character progression, etc.), it is easier to model this using objects, which hold state, instead of pure functions which can not hold information.
Finally, there is just not as much work for functional programmers. There are few to no entry-level functional programming jobs, and object-oriented programming skills are still required in almost any job you find. There can be a lot of inertia in programming, and the cultural resistance to buzzwords in the coding community has made many programmers wary of switching away from the object-oriented programming paradigm. In the past, functional programmers have garnered a reputation for being aloof — often referring to underlying mathematical concepts that are less accessible to the average developer. This attitude has been changing recently and there have been efforts within the functional programming community to gain more widespread adoption. For now, though, object-oriented is the dominant paradigm in the industry.
Functional programming should be learned in the same spirit as reading the Iliad — not because it is an immediately marketable skill, but because it is a useful way to think about the world. It will make you a more efficient programmer and give you a greater toolbox from which to draw on when solving problems. Understanding functional concepts does not mean you need to totally eschew object-oriented ones. The best developers know when it is appropriate to apply functional concepts and when to stick to good old OO programming. A good understanding of functional programming will give you deeper knowledge of coding concepts overall.
If you want to learn more, this medium article goes into a lot more depth about many functional programming concepts that we just touched on above. If you are interested in learning a functional language, first make sure you want to dedicate significant time to learning an entirely new language. If you are sure, Elm is a good language to start with. It is a newish language that targets front-end development and is designed to be easy to learn for people unfamiliar with functional programming.