I’ve been reading about Functional Programming for many years, but as I don’t code in a functional language such as F# or Haskell, I’ve not really had the chance to see how I can make use of FP principles.

Fortunately, as work slows down for the Christmas holidays I’ve now found some spare time to revisit this topic. In this post I’ll give a general overview of FP, and then in future posts I hope to describe how to apply FP principles to C# (my primary language).

What is Functional Programming?

Like many programming concepts, definitions are often subjective. Personally, I thought this definition by Akhil Bhadwal is accurate and concise:

Functional programming is a programming paradigm in which it tries to bind everything in pure mathematical functions. It is a declarative type of programming style that focuses on what to solve rather than how to solve.

But what is a “mathematical function”? It’s simply a mapping from an input to an output. This is opposed to functions typically seen in non-FP programming languages such as C# or Javascript, where the function represents an encapsulated sequence of instructions that performs an action or changes the state of the object.

By applying FP principles we’ll quickly identify the separation between data and behaviour.

Some key FP concepts:

  • Functions are first class: In the FP paradigm, functions are treated as variables; they can be passed as arguments or stored in data structures.
  • Higher-order function: This is a function that receives another function as an argument, or returns another function, or both.
  • Pure function: This is a function that has no side-effects. For a particular input, it always returns the same output.
  • Referential transparency: Because of the nature of pure functions, for a given input we can replace the function with its return value in all subsequent calls to that function.
  • Recursion: There aren’t any for and while loops in FP. Instead, we rely on recursion for iteration.
  • Variables are immutable: It is not possible to modify a variable once it has been initialized. However, we can pass that variable to a function which returns another value.

Advantages of Functional Programming

Controlling Side Effects

One major benefit of FP is the controlling of side effects. In programming, a side effect is anything that happens to the state of a system as a result of invoking a function.

Sometimes this is benign such as writing to a log, but quite often in OO-programing, we have to debug some unexpected behaviour because a method has changed some shared system state.

For example, let us compare the following code snippets:

public class Product
{
    public decimal Price { get; set; }

    public void UpdatePrice(decimal vat, decimal cost, decimal markup)
    {
        this.Price = (cost + markup) * (1 + vat);
    }

    // Rest of class
}
public decimal PriceIncludingVat(decimal vat, decimal cost, decimal markup)
{
    return (cost + markup) * (1 + vat);
}

In the Product class, UpdatePrice changes the value of Price. This is what is meant by a side-effect. It’s a public method, and we may not be aware that another part of the system is calling it.

On the other hand, calling PriceIncludingVat doesn’t modify existing state; it returns new state. You can call it as many times as you want and your price variable won’t change until you actually assign it, e.g. var price = PriceIncludingVat(0.2m, 10m, 2m);

Easier to Understand

When a function has side effects, we not only need to consider its primary result, but also how it affects the rest of the system. This means that as a developer, at any one time, we need to be thinking about multiple system components - it’s mentally exhausting!

However, because pure functions don’t change any states and are entirely dependent on the input, they are simple to understand.

Pure functions clear the way for making complex systems more predictable because they always behave the same way regardless of the external state.

Easier to Test and Debug

We’ve mentioned that FP variables are immutable - this results in our state being predictable.

In OOP, mutable state, especially once we encapsulate the object and put an interface on it, is just not predictable. In fact, it’s so unpredictable that when we test it, we often have to mock things up so that we don’t inadvertently change out state while trying to test things!

But in FP we have immutability, state does not change - there are no side effects. This makes it easier to test and debug our code.

Suited to Asynchronous Execution

Finally, because pure functions don’t change the overall system state, they are naturally more suited for parallel or asynchronous execution.

Disadvantages

  • There is a learning curve to overcome (which I’m now finding!)
  • Immutable values combined with recursion may lead to a performance reduction
  • Using recursion instead of loops can be a daunting task

Further Reading

I am hoping to write a series of blog posts describing practicle ways of applying FP principles in C#. The first of the these has already been published: Using Functional Programming Principles in C# (Part 1).