The functional if

The if statement is a low level flow construct in most imperative programming languages. It is traditionally used to do things like this:

if (some condition is true) {
    execute branch 1 of code
} else {
    execute branch 2 of code
}

where different branches of code represent different execution paths your program could take. It is basically a specific conditional case of a GOTO statement – if some condition holds go to this line; otherwise, go to that line. The common objectives of those branches are:

  • execute code with different side effects
  • assign different values to existing or new variables

I’m going to show how in these common cases you can write more expressive, less error prone code that to certain degree resembles the functional style. The examples will be in PHP, although other languages that support anonymous functions would probably allow similar technique as well.

Let’s look at the difference between procedural vs the functional if.

The procedural style:

$a = 20;
$b = 10;
if ($my_condition) {
    $x = $a + $b;
} else {
    $x = $a - $b;
}

Equivalent functional style, using the ternary operator – http://php.net/manual/en/language.operators.comparison.php:

$x = $my_condition ? $a + $b : $a - $b;

Notice that the right hand side of this line is an expression, not a statement. It always returns a value and, consequently, the $x will always have a value assigned as a result. While in the procedural style, we have to explicitly set it in each branch.

This is important because in procedural style:

  • logic is more error prone, we may forget to assign correct value to $x during certain execution path and not notice
  • programmer is tempted to set other variables in some or all of these exection paths that are used outside of the if block logic
  • more generally, statements execute in current lexical scope, which encourages logic with implicit dependencies on its context

These are all bad things that lead to (1) bugs during runtime, (2) bad code that can’t be easily read, understood and modified.

So, to avoid this, we could do something like this instead:

if ($my_condition) {
    $x = my_func_1($a, $b);
} else {
    $x = my_func_2($a, $b);
}

function my_func_1($a, $b) {
    return $a + $b;
}

function my_func_2($a, $b) {
    return $a - $b;
}

This is better, but a few disadvantages of doing this are:

  • it still suffers from multiple assignment issue
  • it potentially pollutes the current (which may be global) namespace with functions that may not be reusable and makes the code too verbose
  • the if statement doesn’t enforce this pattern, it must be explicitly used everywhere
  • it encourages programmer to create a single
    myfunc($a, $b)

    and move the procedural if logic there instead

Ideally, we’d have a way to:

  • be able to create local variables that don’t affect context
  • provide proper isolation for the logic
  • provide pattern that we can re-use in other places

Basically, we would want a flexible, multi-line ternary operator, or “the functional if.”

In functional programming languages, this is the only way. For example, in Erlang I can say:

X = if my_condition() -> A + B; true -> A - B end.

In fact, if I try to assign (or more precisely, pattern match) the X variable inside the if blocks, I’ll get a compiler warning.

In Lisp:

(setf X (if (my-condition) (+ a b) (- a b)))

But most imperative and procedural programming languages do not provide such features. So how close can we get to this in PHP? Let’s try this syntax:

$x = X::if(
    $my_condition,
    function($a, $b) { return $a + $b; },
    [$a, $b],
    function($a, $b) { return $a - $b; },
    [$a, $b]
);

Here we call X::if() static function that takes 5 arguments:

  • condition that evaluates to true or false
  • anonymous function to execute and return its result if the condition is true
  • array of arguments to pass to true anonymous function
  • anonymous function to execute and return its result if the condition is false
  • array of arguments to pass to false anonymous function

So, how would the X::if() look like? It’s actually pretty simple 3 lines of code:

class X
{
    /**
     * Depending on the condition, executes corresponding function with arguments.
     *
     * @param bool $condition Condition that evaluates to true or false
     * @param callable $true Callable that gets executed if $condition is true
     * @param array $true_args Arguments that get passed to $true callable
     * @param callable $false Callable that gets executed if $condition is false
     * @param array $false_args Arguments that get passed to $false callable
     *
     * @return mixed result of either $true or $false callable execution
     */

    public static function if(
        $condition,
        callable $true,
        array $true_args,
        callable $false,
        array $false_args
    ) {
        $fun = $my_condition ? $true : $false;
        $args = $my_condition ? $true_args : $false_args;
        return call_user_func_array($fun, $args);
    }
}

Now if you can convince your team to get behind this pattern and somehow avoid the WTF moment every time someone looks at it, you might even avoid few bugs and hopefully make your code more readable and easier to modify and reason about.