Introduction: This article on Imperative versus Functional Programming starts off with defining imperative and functional programming paradigms. It then explains how these two paradigms differ considering various factors such as mutability, control flow, order of execution etc. It finally has a look at the road ahead for the paradigms.
What is Imperative Programming: Imperative Programming, also known as procedural programming, is the most prevalent programming style in use today. A program in imperative language specifies how the desired result is to be obtained. I.e. the program specifies the exact steps to be performed to achieve the desired outcome. Common examples of imperative languages are C, Pascal, COBOL, Java(purely imperative prior to version 8) etc.
What is functional programming: A program in functional programming focusses on what is to be done. Put simply, the program declares what needs to be done and the language runtime takes care of achieving that. Functional programming is derived from(or is a subtype of) declarative style of programming. Examples of functional programming languages are Lisp, Scheme, Haskel, Clojure and Java(functional features added from version 8 onwards).
Differences in Imperative and Functional Programming paradigms
- Style of Coding: Code in imperative languages has to list out all the necessary steps to achieve the desired result i.e. the how part.For e.g.: A for loop has to set the initial value of the counter, increment the counter and ensure that the loop does not overrun the size of the data it is operating upon.
Functional Languages, on the other hand, declare what needs to be done. For e.g: In the case of a loop the functional program would just declare a loop and inside it would write the logic to be repeated. The functional language runtime would take care of all iterating requirements of the loop such as incrementing the loop counter etc.
- Mutability of Variables: Variables in imperative languages are inherently mutable in nature. The program is described as a series of expressions which act on variables and alter their values as they keep executing.
Functional programming thrives on immutability of its variables. A lot of flexibility in execution of statements is achieved if the variables are known in advance not to change state.
- Order of Execution: In a procedural language variables are assigned values which undergo changes as the program executes. The values of expressions in the program in turn depend on these variable values. Now, if order of execution is not followed and variables are assigned values out-of-turn then the values of expressions which use these variables may not be correct as a side effect. Order of execution is thus important in imperative languages to avoid such side-effects.
In functional languages, as the variables are immutable, there are no side effects of any changes done to the variables in some other part of the code. Order of execution then becomes immaterial.Moreover, the language designers use this freedom to build flexibility in execution to achieve the best performance.
- Functions as first class objects: In functional programming functions can be passed around as first-class objects to other parts of the code at runtime. This gives the programmer flexibility to alter logic at runtime.
Imperative languages on the other hand rely on passing values as parameters to methods. Called method then passes the computed output back if required. Function objects are not allowed to be passed as parameters to methods.
- Flow control mechanisms: Imperative languages primarily use loops, conditions and methods to move through the execution steps. The language provides these features as it expects the programmer to code the entire flow.
Functional languages rely mainly on functions calls(including recursive calls) to achieve their desired goal. The functional languages keep the low-level control flow in their hand. The language runtime takes care of executing these functions in the most optimized way.
- Primary language structures: In an imperative programming language the data structures used are variables, arrays etc which mutate in state as the program moves ahead.
The primary data structures in functional languages are collections and functions. Developers declare functions which use the immutable collections. If need be then code passes these function definitions to other functions to compose higher order functions.
The way ahead – imperative vs functional: As distributed computing gains more traction, mutability becomes more of an overhead as it prevents efficient concurrency. If a program can be executed only in a particular order and out-of-turn changes to its variables have side-effects then the ability of the language runtime to concurrently execute parts of the code is limited. Thus, imperative programming languages which are not conducive to concurrency are slowly losing ground to functional programming languages such as Scala, Clojure and even Java has introduced functional features from version 8 onwards.
Going by the current industry needs and trends, functional languages seem to be the way ahead for newer big data-fed projects which require distributed/concurrent processing. Having said that imperative languages will continue to hold their own based on the massive amount of code already written with them and that the shift to a new paradigm will take some time.
Summary: We looked at imperative versus functional programming styles and the main differences which separate these two programming paradigms and the way ahead.