Friday, October 30, 2020

Why I prefer functional programming


This post explains why I stick with functional programming, using a rationale that a non-functional programmer can relate to.

The reason is actually pretty simple: functional programming idioms are more enduring and portable than idioms from other programming paradigms (such as procedural or object-oriented programming). To explain why, I need to first define what I understand “functional programming” to mean (which is admittedly an imprecise and vague term).

I personally use the term “functional programming” to denote a style of programming where you restrict yourself as much as possible to the following language features:

  • Scalars, including:
    • Numbers
    • Strings
  • Algebraic data types, including:
    • Records
    • Tagged unions, including:
      • Bools
      • Optional values
      • Enums
    • Recursion, including:
      • Lists
  • First-class functions

Carefully note what’s absent from the list. We don’t mention:

  • Classes / Objects
  • Mutation
  • Structured programming idioms (e.g. for / while loops)

That’s not to say that those features are banned from my definition of functional programming. Think of the definition as more of a “tech radar” where the former set of features fall in the “Adopt” category and the latter set of features fall in the “Hold” category.

So what distinguishes the former “approved” features from the latter “discouraged” features? The approved language features are “timeless”. You’re always going to need numbers, lists, strings, functions, records, etc. They aren’t even specific to programming: they predate programming and originate from good old-fashioned math. If your language doesn’t support one or more of those features you will run into difficulties modeling some problem domains.

However, once you verse yourself in functional programming idioms you realize that you don’t actually need much else beyond those features:

  • Error handling? Use a tagged union (e.g. Either / Result)
  • Loops? Use recursion
  • Dependency injection? Use a higher-order function

When you view things in that light you begin to view other programming idioms as window dressing that comes and goes; not fundamental to the discipline of software engineering.

Moreover, using “timeless” primitives fosters a programming style that is more portable than most. Most functional programming idioms can be ported to any language, with the notable exception of recursion and generalized tagged unions (which not all languages support). However, functional programmers learn how to translate recursion and tagged unions to equivalent idioms in other languages (e.g. loops and the visitor pattern, respectively). However, if you try to port object-oriented idioms to a non-object-oriented language you’re going to have a bad time — likewise for porting imperative idioms to a functional programming language.

This is why my tech radar marks functional programming as “Adopt” and marks other programming paradigms as “Hold”.