Functional programming can make software more reliable. Here's how.
Among the many programming paradigms, functional programming has been in quite a niche for the past 60 years. Although game changers like Google's search algorithm rely on its very key concepts, the average programmer of today knows little to nothing about it. Until recently, object-oriented programming has always taken the crown—and functional programming has been left behind, despite its beauty and applicability.
That's about to change. With the rise of big data, artificial intelligence, and other technologies, functional programming is becoming more and more advantageous. It's therefore no wonder that popular languages like Java and Python are adopting more and more concepts from functional programming. Other languages like Haskell are almost purely functional.
In simple terms, functional programming is all about building functions for immutable variables. That is, once a value is assigned to a variable, this assignment stays until the end. To add more values, one must add more variables. This is useful when dealing with vast amounts of data that shouldn't be copied a million times, to save computing power and memory space.
In contrast, object-oriented programming is about having a relatively fixed set of functions and modifying or adding new variables. This is useful for relatively small datasets but can quickly get out of hand as the data volume increases.
Because of its nature, functional programming is great for in-demand tasks such as data analysis and machine learning. This doesn't mean you should say goodbye to object-oriented programming and go completely functional. It is useful, however, to know about the basic principles so you can use them to your advantage when appropriate.
What makes programs buggy, and how functional programming can help
It's not like there are no functions in object-oriented programming. But often, these functions are muddled with the data and implemented in a manner that easily introduces bugs. This way of coding is easy to learn and makes beginners productive faster. But from the perspective of a functional programmer, they're a stylistic no-go.
The basic idea is that states don't change in functional programming. Therefore, persistent data is never part of a function but rather used to test functions. This alone makes debugging easier because a programmer can quickly see whether a function is misbehaving or a faulty dataset is at the core of an error. In addition, there are other, more theoretical advantages:
- Locality: Not separating data from functions means that data is potentially spread out all over the source code. By separating it off, one can put all data into a few input files. This way, there is less danger of accidentally introducing bugs in the source code when data needs to be changed.
- Timeliness: Because functions don't change states in functional programming, it's easier to determine when data is known, be it while the code is written, when it starts executing, while it's running, or when it's finished. This helps keep an overview over the data and makes debugging easier.
- Structure: It goes without saying that it's easier to get more structure into your code if you separate off the data. That's not to say that object-oriented programming is unstructured; rather, it's easier to create clear source code when following clear guidelines that impose a minimum of structure. This also makes it easier to keep an overview of all functions.
Note that while separating functions and data is indispensable in functional programming, it's completely possible to implement in object-oriented programming. It is therefore one of the ways in which programmers can improve their code through some tricks of functional programming without having to learn anything fundamentally new.
Functional programming is writing pure functions
A pure function is one that always returns the same output for a given input and has no side effects—that is, that modifies data outside of the function. Pure functions are almost a corollary of separating data from functions.
Object-oriented programming effectively encourages side effects by giving them a place within objects. In a large program, this makes debugging harder because the programmer needs to check the whole function for additional dependencies.
In functional programming, only pure functions are allowed. This not only makes debugging a lot easier but also facilitates writing functions inside one another by creating functions that return a function, or functions that take another function as an argument. When facing complex problems, this can be a huge advantage.
These languages are seeing the trend (or not)
While by no means a complete list, the following provides a brief overview of how much popular languages are adopting functional programming.
In stark contrast to other languages, Perl embraces side effects instead of discouraging them. This makes sense, considering its inception as a language for text manipulation, where side effects can indeed be useful. Although Perl does support some functional concepts, I wouldn't try too much functional programming with it.
As an imperative and procedural language, Go isn't the first choice when it comes to functional programming. It is, however, possible to implement recursions, pure functions, and more in a relatively straightforward way.
Programmers who try to write functional code in Java usually end up with code that is littered with static keywords. This doesn't add to the readability of the code and often reverses any gains in readability through using functional concepts. While it is in principle possible, functional programming and Java are not a good match in practice.
Although Swift, being a multi-paradigm language, supports some key concepts of functional programming, resources about it are rather scarce. This could be due to the fact that Swift is still relatively young compared with other languages and its community is smaller than that of others. In any case, other languages like the ones listed below might be a better option to learn some concepts of functional programming.
The C family
Because C is a procedural language, it doesn't support functional programming natively. There are, however, packages like FFCALL that support some elements of functional programming, such as lambda expressions. In a similar way, Objective-C is an imperative language, which makes functional code almost impossible to implement.
C++ supports lambda expressions in a simpler way since version 11; it doesn't support immutable data types, however. It's therefore considered an impure functional programming language. C# is similar in that sense because it also supports some concepts of functional programming, while others are hard to implement.
Just like the two aforementioned languages, Ruby is a multi-paradigm language that supports key concepts such as immutable datasets. This, again, makes it very suitable for functional programming novices.
Scala's goal is to unify object-oriented and functional programming. This seems odd to many users because functional programming aims at eliminating side effects completely while object-oriented programming tries to keep them inside objects.
The point is, however, that Scala is mostly functional, and object-oriented only if functional would be too much of a hassle. This makes it an excellent language to manage transitioning from object-oriented to functional programming.
Python actively encourages functional programming. You can see this by the fact that every function has, by default, at least one input: self. A function without an explicit input is guaranteed to have a side effect, since every function needs some kind of input. This mirrors the Zen of Python: Explicit is better than implicit.
According to its creator, Clojure is about 80 percent functional. All values are immutable by default, just like you need them in functional programming. However, you can get around that by using mutable-value wrappers around these immutable values. When you open such a wrapper, the thing you get out is immutable again.
This is one of the few languages that are purely functional and statically typed. While this might seem like a time drainer during development, it pays off bigly when debugging a program. It's not as easy to learn as other languages, but it's definitely worth the investment.
The beauty and limitations of functional programming
Even though functional programming has many upsides, the ubiquity of object-oriented programming indicates that functional isn't the end of the story. Let's face it: Some of the virtues of functional programming are also its biggest downsides:
- No I/O: One of the most practical features of non-functional programming (that includes object-oriented programming) is that you can process user-generated input and write output to the screen. However, I/O is a side effect in a fundamental way. So, if you want to write purely functional code, you'll have to live with the fact that I/O isn't possible or find a rather complex workaround.
- Recursions and memory usage: One key feature of functional programming is that loops are abstracted away and replaced by recursions. Because these recursions always create new objects instead of manipulating old ones, this can result in rather high memory usage. There are relatively simple workarounds around this issue, but beginners in particular might be tempted to overuse memory initially.
- No beginner-friendliness: Functional programming is directly borrowed from mathematics and, as such, comes charged with a lot of special jargon, proofs, and theorems. This can intimidate beginners. And although one can in principle prove that a functional program is correct, in practice these proofs are rather lengthy and become nearly impossible to understand when the program is large.
- Smaller community: Even though there are quite lively forums for Haskell, Scala, and other languages, the community for object-oriented programming is dozens of times larger. It's therefore more difficult to find solutions to problems by browsing Stack Overflow or related forums, or by asking a colleague.
These drawbacks demonstrate that pure functional programming is often not a good idea. However, including key concepts of functional programming into otherwise object-oriented code can make programs a lot more structured, readable, and easier to debug.
Big data is coming and it's bringing a friend: Functional programming
In contrast to object-oriented programming, functional programming is still a niche phenomenon. If the inclusions of functional programming principles in Python and other languages are of any significance, however, then functional programming seems to be gaining traction.
Even though some languages are adopting few concepts of functional programming or none at all, many popular languages are including them more and more. It turns out that separating data from functions, eliminating side effects, and taking advantage of recursions and nested functions can make a program a lot cleaner and easier to maintain.
Even though it's an old paradigm, it makes sense that functional programming is gaining traction now: Among other things, it's great for big databases, parallel programming, and machine learning. And all these fields have been booming over the past decade.
Functional programming has many virtues worth considering. Although pure functional code is unsuitable in many situations, including some basic functional concepts in existing code, it can make programs much more suitable to the problems they're addressing.
Functional programming: Lessons for leaders
- Functional programming can improve the reliability of software, where practical.
- Sometimes it's best to change programming languages and paradigms based on the nature of the application.
- Old ideas, like functional programming, can find new significance as the tech landscape changes.
- Swift: It isn't just for iPhones anymore
- 4 lessons for modern software developers from 1970s mainframe programming
- Top Linux developers' recommended programming books
A function without an explicit input is guaranteed to have a side effect, since every function needs some kind of input.
This article/content was written by the individual writer identified and does not necessarily reflect the view of Hewlett Packard Enterprise Company.