Truly understanding the difference between procedural and functional
I'm really having a hard time understanding the difference between procedural and functional programming paradigms.
Here are the first two paragraphs from the Wikipedia entry on functional programming:
In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast to the imperative programming style, which emphasizes changes in state. Functional programming has its roots in lambda calculus, a formal system developed in the 1930s to investigate function definition, function application, and recursion. Many functional programming languages can be viewed as elaborations on the lambda calculus.
In practice, the difference between a mathematical function and the notion of a "function" used in imperative programming is that imperative functions can have side effects, changing the value of program state. Because of this they lack referential transparency, i.e. the same language expression can result in different values at different times depending on the state of the executing program. Conversely, in functional code, the output value of a function depends only on the arguments that are input to the function, so calling a function
f
twice with the same value for an argumentx
will produce the same resultf(x)
both times. Eliminating side effects can make it much easier to understand and predict the behavior of a program, which is one of the key motivations for the development of functional programming.
In paragraph 2 where it says
Conversely, in functional code, the output value of a function depends only on the arguments that are input to the function, so calling a function
f
twice with the same value for an argumentx
will produce the same resultf(x)
both times.
Isn't that the same exact case for procedural programming?
What should one look for in procedural vs functional that stand out?
Solution 1:
Functional Programming
Functional programming refers to the ability to treat functions as values.
Let's consider an analogy with "regular" values. We can take two integer values and combine them using the +
operator to obtain a new integer. Or we can multiply an integer by a floating point number to get a floating point number.
In functional programming, we can combine two function values to produce a new function value using operators like compose or lift. Or we can combine a function value and a data value to produce a new data value using operators like map or fold.
Note that many languages have functional programming capabilities -- even languages that are not usually thought of as functional languages. Even Grandfather FORTRAN supported function values, although it did not offer much in the way of function-combining operators. For a language to be called "functional", it needs to embrace functional programming capabilities in a big way.
Procedural Programming
Procedural programming refers to the ability to encapsulate a common sequence of instructions into a procedure so that those instructions can be invoked from many places without resorting to copy-and-paste. As procedures were a very early development in programming, the capability is almost invariably linked with the style of programming demanded by machine- or assembly-language programming: a style that emphasizes the notion of storage locations and instructions that move data between those locations.
Contrast
The two styles are not really opposites -- they are just different from one another. There are languages that fully embrace both styles (LISP, for example). The following scenario may give a sense of some differences in the two styles. Let's write some code for a nonsense requirement where we want to determine if all of the words in a list have an odd number of characters. First, procedural style:
function allOdd(words) {
var result = true;
for (var i = 0; i < length(words); ++i) {
var len = length(words[i]);
if (!odd(len)) {
result = false;
break;
}
}
return result;
}
I'll take it as a given that this example is comprehensible. Now, functional style:
function allOdd(words) {
return apply(and, map(compose(odd, length), words));
}
Working from the inside out, this definition does the following things:
-
compose(odd, length)
combines theodd
andlength
functions to produce a new function that determines whether the length of a string is odd. -
map(..., words)
calls that new function for each element inwords
, ultimately returning a new list of boolean values, each indicating whether the corresponding word has an odd number of characters. -
apply(and, ...)
applies the "and" operator to the resulting list, and-ing all of the booleans together to yield the final result.
You can see from these examples that procedural programming is very concerned with moving values around in variables and explicitly describing the operations needed to produce the final result. In contrast, the functional style emphasizes the combination of functions required to transform the initial input to the final output.
The example also shows the typical relative sizes of procedural versus functional code. Furthermore, it demonstrates that the performance characteristics of procedural code might be easier to see than that of functional code. Consider: do the functions compute the lengths of all of the words in the list, or does each stop immediately after finding the first even length word? On the other hand, the functional code permits a high-quality implementation to perform some pretty serious optimization since it primarily expresses intent rather than an explicit algorithm.
Further Reading
This question comes up a lot... see, for example:
- What is the difference between procedural programming and functional programming?
- Can someone give me examples of functional programming vs imperative/procedural programming?
- OOP vs Functional Programming vs Procedural
John Backus' Turing award lecture spells out the motivations for functional programming in great detail:
Can Programming Be Liberated from the von Neumann Style?
I really shouldn't mention that paper in the present context because it gets pretty technical, pretty quickly. I just couldn't resist because I think it is truly foundational.
Addendum - 2013
Commentators point out that popular contemporary languages offer other styles of programming over and above procedural and functional. Such languages often offer one or more of the following programming styles:
- query (e.g. list comprehensions, language-integrated query)
- dataflow (e.g. implicit iteration, bulk operations)
- object-oriented (e.g. encapsulated data and methods)
- language-oriented (e.g. application-specific syntax, macros)
See the comments below for examples of how the pseudo-code examples in this response can benefit from some of the facilities available from those other styles. In particular, the procedural example will benefit from the application of virtually any higher-level construct.
The exhibited examples deliberately avoid mixing in these other programming styles in order to emphasize the distinction between the two styles under discussion.
Solution 2:
The real difference between functional and imperative programming is the mindset - imperative programmers are thinking of variables and blocks of memory, whereas functional programmers are thinking, "How can I transform my input data into my output data" - your "program" is the pipeline and set of transforms on the data to take it from the Input to the Output. That's the interesting part IMO, not the "Thou shalt not use variables" bit.
As a consequence of this mindset, FP programs typically describe what will happen, instead of the specific mechanism of how it will happen - this is powerful because if we can clearly state what "Select" and "Where" and "Aggregate" means, we are free to swap out their implementations, just like we do with AsParallel() and suddenly our single-threaded app scales out to n cores.