Pure Functions

Overview: Striving to write pure functions (i.e., functions that are consistent and side-effect free) improves the testability, simplicity, and clarity of code.

What are Pure Functions?

Pure functions are consistent and side-effect free. A consistent function returns the same value every time for a particular set of arguments (this type of function is said to be referentially transparent, as calls to the function can be replaced by the return value without changing the program’s behavior.) A side-effect-free function does not change state through any means beyond its return value, meaning the values that existed before the function call (e.g., global variables, disk contents, static instances, UI, etc.) were not directly altered by the function; and it does not read any state beyond it’s arguments (i.e., no reading of data from files, databases, etc.) Think of pure functions like Mr. Spock: given a set of inputs, you will always get the same straight-forward, logical result (okay, okay, Spock showed an unpredictable, emotional response in “Amok Time”, but c’mon, he thought he had killed Captain Kirk.)

You don’t have to be using some fancy-pants functional programming language to benefit from pure functions. In languages that aren’t purely functional, you’ll have to work to avoid things like side effects and pay attention to whether the arguments you’ve received are copies or references, semantics that are language/context dependent. When dealing with references, you should treat them like you treat dad’s favorite belongings (like a special lamp, for instance): you can look (read the values), but don’t touch (edit the values)!

Examples of Pure and Impure Functions

Let’s work through some example functions and determine if they’re pure (i.e., consistent and side-effect free) or impure.

Below is a trivial example of a JavaScript function that returns the square of a number.

function square(x){
    return x * x;
}

Given a particular number x, this square function will always return the same result, so it is consistent. Additionally, it makes no changes to the global state beyond its return value. Therefore, it’s a pure function.

Next, an example Javascript function that checks out a book.

function checkOutBook(book, patron){
    if(book.isCheckedOut){
        return false;
    }
    // changes to the book object alter the object beyond the scope of this function
    book.isCheckedOut = true;
    book.checkedOutTo = patron;
    return true;
}

The function is consistent, as passing in a particular set of arguments will always return the same result. However, the function changes some of the properties of the book object, changes that will persist even after the function has returned, so this function has side effects. Therefore, it’s an impure function.

The Benefits of Pure Functions

Pure functions facilitate simplicity and clarity. Because pure functions lack side effects, the outside world is completely abstracted away and the programmer can focus entirely on the parameters and control flow constructs contained within the function. Additionally, when calling a pure function, the programmer can focus solely on the visible context of the call and the return value, as the function has no other impact on state.

Testing pure functions proves extremely straight-forward. All possible paths/states of a pure function can be directly achieved by passing in different sets of arguments. The only things you’ll be mocking are Lions Fans (sure, we didn’t end the season well, but we really could have a great season next… oh, the abject sadness.)

A Usage Strategy for Pure Functions

Because of the benefits of pure functions, I follow the simple rule, “Strive for purity.” That is to say, I work hard to write as many functions as I can in a pure form, and when needed, I write functions that have side effects or are inconsistent.

Side effects aren’t bad. Any meaningful program will have side effects, and it doesn’t bother me in the least when it’s time to write an impure function. However, I try to keep the side effects isolated in small fall-through functions, so as to simplify the simplicity, clarity, and testability of the rest of the code base.

Return To Me: A Song About Our Walk With God

I’ve completed the basic arrangement of a new song: Return To Me. The song takes the perspective of God singing to us, his children, throughout our journey with him. The song ends with us singing a chorus of “Hallelujah’s” to him, our God. You’ll have to use your imagination for now, as the melody is voiced with cello until I can complete a vocal version, which will hopefully include SATB parts for the chorus, too.

The song describes our need for God, our journey with God, and the love to which God has called us for all eternity. The lyrics and corresponding scriptural references are posted below the video.

My parents, Richard and Marjorie Richardson, inspired much of the work on the song, as did the precious example set by Laney and her family over the past few months. Davin Granroth and Rodney Page took the time to provide encouraging feedback on the work.

Return To Me (Instrumental)

Return To Me (Lyrics)

“Return to me for I still love you.”
Joel 2:13
Return to the Lord your God, for he is gracious and merciful, slow to anger, and abounding in steadfast love; and he relents over disaster.

“Return to me for I’ve redeemed you.”
Isaiah 44:22
I have blotted out your transgressions like a cloud and your sins like mist; return to me, for I have redeemed you.

“I so loved you, I laid my life down.”
1 John 3:16
By this we know love, that he laid down his life for us, and we ought to lay down our lives for the brothers.

“Come back home my wayward child.”
Jeremiah 3:14 & 3:22 (NLT AND NET bible) on wayward children.

“Walk with me and you will find rest.”
Jeremiah 6:16
Thus says the Lord: “Stand by the roads, and look, and ask for the ancient paths, where the good way is; and walk in it, and find rest for your souls.

“Walk with me and you will know hope.”
Ephesians 1:15 – 21
15 For this reason, because I have heard of your faith in the Lord Jesus and your love[f] toward all the saints, 16 I do not cease to give thanks for you, remembering you in my prayers, 17 that the God of our Lord Jesus Christ, the Father of glory, may give you the Spirit of wisdom and of revelation in the knowledge of him, 18 having the eyes of your hearts enlightened, that you may know what is the hope to which he has called you, what are the riches of his glorious inheritance in the saints, 19 and what is the immeasurable greatness of his power toward us who believe, according to the working of his great might 20 that he worked in Christ when he raised him from the dead and seated him at his right hand in the heavenly places, 21 far above all rule and authority and power and dominion, and above every name that is named, not only in this age but also in the one to come.

“I so loved you, I laid my life down.”
1 John 3:16
By this we know love, that he laid down his life for us, and we ought to lay down our lives for the brothers.

“Come on home my little child.”
Matthew 19:14
…but Jesus said, “Let the little children come to me and do not hinder them, for to such belongs the kingdom of heaven.”

“I take great delight in you. Let me quiet you within my love.”
Zephaniah 3:17
The Lord your God is in your midst, a mighty one who will save; he will rejoice over you with gladness [other translations read “take delight in you”]; he will quiet you by his love; he will exult over you with loud singing.

“Come home with me. Your place is prepared.”
John 14:2-3
In my Father’s house are many rooms. If it were not so, would I have told you that I go to prepare a place for you? And if I go and prepare a place for you, I will come again and will take you to myself, that where I am you may be also.

“Come home with me and worship The King”
Revelation 19

“I so loved you, I laid my life down.”
1 John 3:16
By this we know love, that he laid down his life for us, and we ought to lay down our lives for the brothers.

“Welcome home my precious child.”
Matthew 19:14
…but Jesus said, “Let the little children come to me and do not hinder them, for to such belongs the kingdom of heaven.”

“Nothing in all creation can separate you from my love.”
Romans 8:38-39
For I am sure that neither death nor life, nor angels nor rulers, nor things present nor things to come, nor powers, nor height nor depth, nor anything else in all creation, will be able to separate us from the love of God in Christ Jesus our Lord.

“Hallelu! Hallelujah!”
Revelation 19

Making Concurrent cURL Requests Using PHP’s curl_multi* Functions

The cURL library proves a valuable resource for developers needing to make use of common URL-based protocols (e.g., HTTP, FTP, etc.) for exchanging data. PHP provides a set of curl* wrapper functions in an extension that nicely integrates cURL’s functionality.

When you have to make multiple requests in a script, it’s often more efficient to utilize the curl_multi* functions (e.g., curl_multi_init), which make it possible to process requests concurrently. For example, if you have to make 2 web requests in a script and each one requires 2 seconds to complete, making 2 separate curl requests, one right after the other, requires 4 seconds. However, if you make use of the curl_multi* functions, the requests will be made concurrently (i.e., we no longer have to wait for one request to finish to start the next one), and requires only 2 seconds (the actual execution time depends on if the scripts are truly running in parallel or merely concurrently.)

Let’s take a look at a function that provides a simple interface to the concurrent capabilities of cURL and is extensible to most situations, as the curl_multi* functions can be cumbersome.

/**
* Simple wrapper function for concurrent request processing with PHP's cURL functions (i.e., using curl_multi* functions.)
*
* @param array $requests Array containing request url, post_data, and settings.
* @param array $opts Optional array containing general options for all requests.
* @return array Array containing keys from requests array and values of arrays each containing data (response, null if response empty or error), info (curl info, null if error), and error (error string if there was an error, otherwise null).
*/
function multi(array $requests, array $opts = [])
{
    // create array for curl handles
    $chs = [];
    // merge general curl options args with defaults
    $opts += [CURLOPT_CONNECTTIMEOUT => 3, CURLOPT_TIMEOUT => 3, CURLOPT_RETURNTRANSFER => 1];
    // create array for responses
    $responses = [];
    // init curl multi handle
    $mh = curl_multi_init();
    // create running flag
    $running = null;
    // cycle through requests and set up
    foreach ($requests as $key => $request) {
        // init individual curl handle
        $chs[$key] = curl_init();
        // set url
        curl_setopt($chs[$key], CURLOPT_URL, $request['url']);
        // check for post data and handle if present
        if ($request['post_data']) {
            curl_setopt($chs[$key], CURLOPT_POST, 1);
            curl_setopt($chs[$key], CURLOPT_POSTFIELDS, $request['post_array']);
        }
        // set opts 
        curl_setopt_array($chs[$key], (isset($request['opts']) ? $request['opts'] + $opts : $opts));
        curl_multi_add_handle($mh, $chs[$key]);
    }
    do {
        // execute curl requests
        curl_multi_exec($mh, $running);
        // block to avoid needless cycling until change in status
        curl_multi_select($mh);
    // check flag to see if we're done
    } while($running > 0);
    // cycle through requests
    foreach ($chs as $key => $ch) {
        // handle error
        if (curl_errno($ch)) {
            $responses[$key] = ['data' => null, 'info' => null, 'error' => curl_error($ch)];
        } else {
            // save successful response
            $responses[$key] = ['data' => curl_multi_getcontent($ch), 'info' => curl_getinfo($ch), 'error' => null];
        }
        // close individual handle
        curl_multi_remove_handle($mh, $ch);
    }
    // close multi handle
    curl_multi_close($mh);
    // return respones
    return $responses;
}

To use this function, you can call it like so:

$responses = multi([
    'google' => ['url' => 'http://google.com', 'opts' => [CURLOPT_TIMEOUT => 2]],
    'msu' => ['url'=> 'http://msu.edu']
]);

And, then you can cycle through the responses:

foreach ($responses as $response) {
    if ($response['error']) {
        // handle error
        continue;
    }
    // check for empty response
    if ($response['data'] === null) {
        // examine $response['info']
        continue;
    }
    // handle data
    $data = $response['data'];
    // do something extraordinary
}

While the above function is helpful for a few requests, if you need to make a large number of requests (perhaps more than 5), then instead you should have a look at the rolling curl library, which makes better use of resources.

And your significant other said you couldn’t multitask 🙂

Fall-Through Functions

When embracing functional programming principles in languages that aren’t designed specifically for functional programming, dealing with side effects requires great care and discipline. For those who can’t remember what side effects are, side effects are attempts to modify the state of the world (at least in terms of the scope of your program’s environment) through a means other than the return value of a function (e.g., performing a SQL insert, printing text to the standard output device, sending an email, etc.) Hopefully you noticed the word “attempts.” The problem with trying to directly modify the state of the world is that you don’t know what state the world is in: sometimes we’re caught by surprise.

I try to compartmentalize side effects in functions that lack branching constructs (e.g., if/then, switch, etc.) I refer to this type of function as a fall-through function because the function proceeds line-by-line until it reaches the last line and returns the status or result. Here’s a simple example of a fall-through function in PHP that sends an email:

<?php

$mail = function($to, $subject, $message){
    // handle longer lines
    $message = wordwrap($message, 70, "\r\n");
    // send message, returning status
    return mail($to, $subject, $message);
};

?>

Fall-through functions provide clean separation of the logic we want to test from the world-dependent states that are unpredictable (i.e., code containing side effects), and as we know, clear boundaries are a good thing.