“moving parts.” Rather than build mechanisms to control mutable state, most functional
languages try to remove mutable state, a “moving part.” The theory follows that if the
language exposes fewer potentially error-prone features, it is less likely for developers
to make errors. I will show numerous examples throughout of functional programming
eliminating variables, abstractions, and other moving parts.
In object-oriented imperative programming languages, the units of reuse are classes
and the messages they communicate with, captured in a class diagram. The seminal
work in that space, Design Patterns: Elements of Reusable Object-Oriented Software (by
Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides), includes at least one
class diagram with each pattern. In the OOP world, developers are encouraged to create
unique data structures, with specific operations attached in the form of methods. Func‐
tional programming languages don’t try to achieve reuse in quite the same way. In
functional programming languages, the preference is for a few key data structures (such
as list, set, and map) with highly optimized operations on those data structures. To
utilize this machinery, developers pass data structures plus higher-order functions to
plug into the machinery, customizing it for a particular use.
Consider a simplified portion of the code from Example 1-2:
regexToList(words, "\\b\\w+\\b").stream()
.filter(w -> !NON_WORDS.contains(w))
To retrieve a subset of a list, call the filter() method, passing the list as a stream of
values and a higher-order function specifying the filter criteria (in this case, the syn‐
tactically sugared (w → !NON_WORDS.contains(w))). The machinery applies the filter
criteria in an efficient way, returning the filtered list.
Encapsulation at the function level allows reuse at a more granular, fundamental level
than building new class structures for every problem. Dozens of XML libraries exist in
the Java world, each with its own internal data structures. One advantage of leveraging
higher-level abstractions is already appearing in the Clojure space. Recent clever inno‐
vations in Clojure’s libraries have managed to rewrite the map function to be automat‐
ically parallelizable, meaning that all map operations get a performance boost without
developer intervention.
Functional programmers prefer a few core data structures, building optimized machi‐
nery to understand them. Object-oriented programmers tend to create new data struc‐
tures and attendant operations constantly—building new classes and messages between
them is the predominant object oriented paradigm. Encapsulating all data structures
within classes discourages reuse at the method level, preferring larger framework-style
reuse. Functional programming constructs make it easier to reuse code at a more atomic
level.
Consider the indexOfAny() method, from the popular Java framework Apache Com‐
mons, which provides a slew of helpers for Java, in Example 1-3.
6 | Chapter 1: Why