Why All Developers Should Learn Functional Programming

Last Friday, I turned up to work completely unaware that I’d be spending the rest of the day at the CodeMania programming conference – it was a nice surprise to say the least. The most poignant presentation for me, was Ivan Towlson’s ‘How to Not Write a For Loop’, as he touched on many ideas I’ve been thinking about in the last year since I embraced functional programming myself. Through examples written in imperative C#, Linq and F#, he put forward a fairly compelling argument for why programmers should consider using functional style constructs instead of just banging out the same old for/foreach loops to solve every problem in existence. Compelling enough to prompt me to blog about my strong opinions on the matter.

Functional programming has existed for over half a century but has never really gained much traction until relatively recently. There are niche areas where it clearly shines (real time systems, parallelism etc.), but for the most part, it has been largely confined to obscure languages and dusty academic tomes. Part of the reason for that is that in the past, it has required programmers to step away from the mainstream languages they tend to be comfortable with, to drop everything they know about programming in the traditional imperative style, and to adopt a completely new mindset, in the wake of a steep learning curve full of monads and other mathematical morsels.

But then something great happened… Microsoft released Linq. Now, criticise them all you like, but Linq really is a very well thought-out library. It’s not that C# is the first popular language to incorporate functional-style operations (Python has had them for aeons) or that Linq is even the best example. It’s the fact that Microsoft exposed a massive sector of the programming world to a new way of thinking by injecting functionally inspired, yet accessible constructs into C#. And Linq is an utter joy to use.

So here are a couple of everyday operations which are far better expressed in a functional manner – the operation of finding a human called Aberforth, and the operation of finding all humans who are unlucky enough to have one-eared cats. Firstly, in C# imperative:

Human humanCalledAberforth = null;
foreach (Human human in humans)
{
  if (human.Name == "Aberforth")
  {
    humanCalledAberforth = human;
    break;
  }
}

var unfortunateHumans = new List<Human>();
foreach (Human human in humans)
{
  foreach (Cat cat in human.PetCats)
  {
    if (cat.NumEars == 1)
      unfortunateHumans.Add(human);
  }
}

And the Linq version is below. To understand it, you need to know the following:

  • a => b is lambda shorthand for a function which takes one argument (a) and returns b.
  • Since the below Linq methods are functional in nature, they take some input, perform some computation, and return output, without altering the input which is treated as immutable.
  • FirstOrDefault() searches through a sequence and finds the first element which satisfies a predicate, or returns the default value (null in this case) if it can’t find one.
  • Where() filters a list, based on a predicate. Any() returns true if there are any elements in a sequence which satisfy the specified predicate.
var humanCalledAberforth = humans.FirstOrDefault(
  human => human.Name == "Aberforth");
var unfortunateHumans = humans.Where(
  human => human.PetCats.Any(cat => cat.NumEars == 1) );

Observe that the imperative example is huuuge. A random programmer cannot glance at it and instantly understand its intention – they firstly must mentally process about five times as much code. Furthermore, like most list operations written in an imperative style, it’s packed with boilerplate ifs and loops and temporary variables which aren’t at all representative of the problem the code is actually solving. On the other hand, as soon as I see FirstOrDefault() in the Linq version, I know that the entire operation returns the first human which satisfies some condition… and then I look at the condition, and I’m done.

Essentially, what you realise when first coding in this style is that the majority of things you usually would do with loops can be better represented in terms of higher level standard list operations (projecting, filtering, ordering, aggregation etc.), which are conveniently first class citizens in functional languages/libraries. So for the same reason that you use if and for instead of goto, and foreach instead of for, it makes sense here to use functional list operations instead of overly general Computer Science 101 control flow primitives. The tiny cost is that you have to invest a little time learning about them.

Now I’m not insisting that all programmers write absolutely everything in a functional style, as there are many cases when an imperative style leads to more comprehensible (or more performant) code. I simply think it’s beneficial that programmers learn either a purely functional language, or at least a functional style library. Either will change the way you think about programming. I know that learning a bit of Python and Haskell, and using Linq on a daily basis has permanently warped my mind for the better.

 

About Nathan Pitman

Undergrad software engineer at the University of Auckland
This entry was posted in C#, Functional Programming and tagged , , , , , , . Bookmark the permalink.

One Response to Why All Developers Should Learn Functional Programming

  1. David says:

    Nice post! I agree with everything, except I’m not yet convinced that making everything functional is a bad idea. I need to flesh out my ideas more, but my thoughts so far are:

    1. Express the output of the program as a function of all inputs ever. So something like key presses would be a list of (key, time) pairs.

    2. Specify certain functions that should be evaluated in full and their result cached. This is essentially your program state, and avoids either the memory usage or processing time inflating as time goes on. Everything else can be lazily evaluated.

    That is about as far as I have got. But the hope is that it forces you to do things more nicely, like for example you can’t do:
    if (pressed(‘q’)) {
    importantVariable = null; // Haha, you will never find me deep within the pages of code!
    }

    You have to go:
    importantVariable = if (contains(pressed, ‘q’)) then null else …

    And the special case is right there where the “variable” is defined. I’m hoping this might make code analysis easier for both machines and humans, but I’m still very vague on details so I’m not sure.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>