DEV Community

Discussion on: Explain functional programming to me like I'm five

Collapse
 
ahferroin7 profile image
Austin S. Hemmelgarn

In it’s purest sense, functional programming comes down to one simple principle:

‘Everything is a function.’

Functions are, of course, functions. Variables are functions that return their value. Modules are functions that return their contents. This has a couple of interesting implications that lead logically to many of the other things often associated with functional programming, namely:

  • ‘methods’ as a concept don’t really exist. Unlike OOP languages where you get some special handling that hands you the value the method is being called on in some way inherent to invoking the method, functional languages require whatever data is being operated on to be explicitly passed into the function. For example, the builtin functions map() and reduce() in Python both use calling conventions that would be seen in many functional languages, explicitly taking the iterable/enumerable that they will be operating on as their first argument. This, in turn, lends itself easily to dependency-injection design patterns, which makes testing and interoperability much easier.
  • As a general rule, once defined a function cannot be modified without completely redefining it (essentially, you can’t modify the code of a function in-place). Essentially, functions are inherently immutable once defined. Thus, because everything is a function, all data is immutable in (most) functional languages. This has a number of secondary benefits, one of the biggest ones being that it means that passing data around becomes a zero-copy operation (because the data can’t change out from under you, it’s perfectly safe to just pass references to the data around instead of the data itself. This also means that values passed into a function cannot be modified by the function.
  • Because everything is a function, it must be possible for functions to receive other functions as arguments, and return other functions as parameters. This lets you do all kinds of interesting things, such as writing functions that produce new functions based on their arguments, or wrap other functions to do special argument handling (such as currying and memoization). This is something that many non-functional languages have picked up as well (see for example how functions in Python are actually objects, and thus can be passed around like anything else), and is an important requirement for implementing the concept of decorators.

In addition, there are a number of other things often associated with functional languages that follow logically from functions being such a core part of the language but aren’t a strict requirement for the language to be functional, with the two biggest ones being

  • Special significance and focus is placed on pure functions. A ‘pure’ function is one which has exactly zero side-effects other than transforming the arguments into the return value. Pure functions are inherently thread-safe, can be eliminated from the final machine code safely if their return value is not used, allow for caching of results of complex computations that they do, etc.
  • Recursion is the preferred method of iterative evaluation. Most functional languages provide a special optimization to handle this known as ‘tail-call optimization’. The exact meaning of this isn’t entirely relevant, but languages which do this allow for a theoretically infinite number of sequential function calls provided the functions are structured correctly. Further, in cases where recursion is not possible, the preferred structure of a loop is that the loop body is a function body which takes the loop parameters as arguments (see for example the Enum.each/2 function from Elixir, it takes an enumerable and a function, and then evaluates that function for each item in the enumerable).
Collapse
 
vampiire profile image
Vamp

this was a fantastic answer. maybe a bit beyond 5 but well worth it. with a few code snippet examples this would be great as it’s own post.