Functional Programming for WordPress Developers Part 1
f of x. Those words probably give you nasty flashbacks to a middle school math class with your algebra teacher laboriously graphing a function across the chalkboard. We all had $100 graphing calculators sitting on our desks in my day, but they all still drew out those graphs by hand. What’s with that?
y = f(x) = x + 1. When x is 1, y equals 2. Feed in a value, get another value in return. From that basic principle, you learned to graph circles, sine waves, and conic sections. You learned to compute areas and derivatives by plugging values into formulas.
Functional Programming brings that dependability to programming. Functional programmers strive for mathematical purity in their code, resulting in functions that are consistent, easier to test, and ideally easier to understand. It’s not a silver bullet. It’s just another way of thinking about the code you write.
Functional Programming became a bit of a fad a couple years ago. But it isn’t new at all. It’s one of the four programming paradigms in use since the early 1960s.
- Imperative programming expresses a program as a sequence of steps, analogous to how a computer actually executes a program or how a person might cook according to a recipe.
- Structured programming builds on imperative programming, letting programmers reuse code as subroutines (functions).
- Object-Oriented programming bundles state and functions into objects, which are meant to model abstract as well as real-world concepts.
- …and then there’s Functional Programming!
Principles of Functional Programming
It’s hard to pin down an exact definition of Functional Programming, but there’s a couple of principles programmers look for:
- Referential transparency: When a function is passed the same parameters, it returns the same value. This makes software functions more like the ones you wrote in math class. A function with referential transparency is easier to test and debug because it always does the same thing.
- Minimal state: State refers to the values of global variables, the contents of files, databases, I/O devices; any value not under a function’s direct control. If computers didn’t track state somewhere, our industry wouldn’t have gotten past Hello World. In fact, printing “Hello World” affects the state of an output device, doesn’t it? Functional Programmers pass state around as parameters to functions, or do their best hide it in special containers called monads.
- No side effects: A function that computes the sum of $x and $y has no business adding another floor to the Empire State Building. Functions should do one thing each, and return a result without changing their parameters’ values, or anything else for that matter.
Let’s explore these principles by looking at a function from WordPress itself, one of my favorites.
absint() has perfect referential transparency. No matter what value you pass it, you’ll always get the same result back. It doesn’t affect any variables outside itself, it doesn’t output anything to the browser, and it doesn’t touch the filesystem or the database. There’s no side-effects.
absint() takes the thing you passed, gets its value as an integer, and returns that integer’s absolute value.
- absint(5) is always 5
- absint(“5”) is always 5
- absint(-5) is always 5
- absint(“wordpress”) is always 0
I love functions like absint() because of how predictable they are. Look at some absint() test cases proposed in Trac ticket #28559. The unit test class doesn’t need any setup or teardown. It just passes a value to absint(), makes sure the result matches what’s expected, and repeats.
Pure vs. impure
Languages like Haskell are designed around Functional Programming, and only Functional Programming. They’re considered purely functional languages.
WordPress couldn’t be made purely functional without a major rewrite. But, that shouldn’t stop you from writing purely functional code that interacts with it. Even if a language or application isn’t purely functional, individual functions are still considered pure if they reflect the functional principles.
There’s a lot of global variables in WordPress, but pure functions don’t need to deal with them directly. Instead of functions relying on global variables like $post, try passing $post or even $GLOBALS around as parameters between your functions.
$GLOBALS is a PHP feature that acts like a big associative array that contains every global variable. If your pure function expects to be passed this global state as a big array, you could substitute a different array in your unit tests. If the function has referential transparency, that means it won’t matter. All that matters is that the substitute has the same array keys & values your code expects in $GLOBALS.
When you can’t avoid dealing with global state, write a wrapper around your nice, pure function just to handle those icky impurities. It’s ok, the Functional Programming Police aren’t going to come for you if you if you write a couple impure functions along the way.
In this example, _capitalize_the_post_title() is pure. You can predict what the result will be for a given $post because it has referential transparency. Imagine how easy it’d be to write unit tests for this function! You wouldn’t need to pass a WP_Post object, just a plain object with a post_title.
capitalize_the_post_title() handles the messy job of dealing with global state. In fact, that’s all it does. It doesn’t try to do anything with that data other than pass it to a pure function and return the result.
Now that you’re familiar with some of the principles behind Functional Programming, part 2 will explore first-class functions, composition, and point-free style