A Comparison of Programming Techniques Contrasting Functional Programming and Imperative Programming
A Comparison of Programming Techniques Contrasting Functional Programming and Imperative Programming
Contents
1. Abstract .......................................................................................................................................... 2
2. Introduction.................................................................................................................................... 2
2.1 Data Structure ....................................................................................................................... 3
2.2 Mutability and Side-effects .................................................................................................. 3
2.3 Ease of Implementation....................................................................................................... 4
2.4 Efficient and Readability ...................................................................................................... 6
3 Summary ....................................................................................................................................... 7
Reference .............................................................................................................................................. 8
1
1. Abstract
Building computer applications starts with creating abstractions that model problems or
solutions. To describe these abstractions into something that computers can understand and
execute, programming languages were introduced. Programming languages can be
categorized into different paradigms.
In this paper, Functional and Imperative programming paradigms are compared and
contrasted, using a variety of criteria, such as, data structures, mutability, side effects, ease
of implementation and efficiency.
2. Introduction
Developing software systems is about creating abstractions to model problems and
solutions, and then applying these abstractions to the task that needs to be done. In order to
do that, programming languages were developed out of common need for a basic set of
abstractions, such as data types. In principle, programmers specify what should be done and
how it should be done (Kristiansen, 2001). In imperative programming, the compiler would
follow programmer’s instructions to the letter to do something, because imperative
programming reflects the concept of computation that is built into the modern computer
hardware (Jones and Wadler, 1992). Imperative languages, such as C++ and Java specify
both what and how a problem should be approached by using sequences of statements that
change the state of program.
Consequently, you can consider that an imperative compiler is less sophisticated than a
functional one. Even though, functional programming is straightforward, using it to build
complete applications is very difficult. Additionally, functional programming limits what
programmers can do. For example, functional languages do not give programmers any
control over how program inputs are processed. As a result, programmers have no options
but to alleviate the impact of any defects or bugs in the underlying language and depend on
the providers of the functional languages to tackle the issues.
2
2.1 Data Structure
In imperative programming, programmers have many efficient data structures at their
disposal to solve any particular problem (Fokker, 2003). Unfortunately, functional
programmers do not have this advantage. Although some imperative data structures can be
easily adapted in functional languages, most cannot, because these data structures use
assignments to update variables, which are disallowed or at least discouraged in functional
languages. Assignments or destructive updates can be hazardous when misused, but
effective when used correctly. However, this discouragement of using assignments makes
designing and implementing efficient functional data structures more difficult than imperative
ones. Another major obstacle of designing efficient functional data structures is pattern
matching, which is one of the popular features in functional programming. The reason is that
pattern matching can be performing only on data structures whose representation is known
in advance. This leads many functional programmers to abandon developing advanced data
structures in favour of simple known ones such as lists.
Moreover, functional data structures are expected to be more flexible than their imperative
ones. Imperative data structures are ephemeral, meaning that after updating an imperative
data structure, the old version of the data structure will be replaced by the new data structure
and the old version will not be available anymore (Hartel, 1999). On the other hand,
functional data structures are persistent, as they preserve the previous version of data
structures when modified, i.e. when a functional data structure is updated, both the old and
new versions of the data structure will be available. Although functional data structures have
the same time complexity as imperative ones, they have higher space complexity as they
avoid overwriting the existing values in memory. However, functional data structures are
immutable, which means they are very thread-safe. In addition, immutable data structures
are quite simpler and have higher security as they disallow overwriting any parts of the data
that are shared.
3
program, therefore such changes have side effects. These side effects make imperative
programs not readable, for example, the returned result from a function depends on what
happened during the execution of other functions. Moreover, these side effects make
imperative programs not reusable as every function depends on the program’s global
environment. Furthermore, because of these side effects the correctness of imperative
programs is almost impossible.
Conversely, functional programs evaluate expressions, which can have values of any type,
including functions and large data structures. This simplicity of functional computations helps
in developing programs that separate concerns, reuse code and provide comprehensible
interface between programs (Fischer, Kiselyov, and Shan, 2011). In functional programming,
all classes are immutable, whose instances cannot be modified. Such classes and objects
can only be in one state, all of the data contained in each instance is provided when it is
created and cannot be modified across threads. By using immutable data structures,
programmers can eliminate the hard to detect bugs. Additionally, immutable classes are
easier to design and less prone to error and are more secure.
Furthermore, pure functional programming has no side effects, because functional programs
evaluate expressions rather than execute commands. Every function in functional
programming is defined by an expression and each expression is formed by applying
function to other expressions. Additionally, every expression has a value and a computation
evaluates the value of an expression. In functional programming, variables represent
constant values, instead of memory locations and functional programming discourages the
modification of variable values.
Moreover, because imperative programs manipulate pointers and references to values, the
memory that is needed to store these values must be allocated and de-allocated explicitly.
This can make imperative programming to have more control over programs’ execution and
the memory representation of data. However, this also can lead to errors such as memory
leaks, which can affect the performance of applications and the operating system they are
running on. In addition, as imperative languages are closer to the actual machine
4
representation, code written in imperative languages can be more efficient but prone to
runtime errors.
Finally, imperative languages implements iterations through loops, but can also implement
recursion. In principle, iterations through loops use destructive updates, which make
programs to have side effects. On the other hand, a functional program cannot be iterative
5
because the value of the condition of the loop never differs. Functional languages uses
recursion or explicit calls to other functions i.e. map, to carry out iterative process.
Bird and Wadler (2014) argue that the use of functional languages allow for greater
extensibility, agility and offer more productive ways of developing software systems, mainly
due to functional programs to be only 12 percent as large as imperative ones. Even though,
this is true in certain problem areas, for other problem areas, functional solutions are 30
percent as large as imperative ones to the similar problems. Nevertheless, the size of a
program code alone is not a good way to determine its efficiency and productivity, as not all
lines of code have same complexity or take the same amount of time to produce. Actually,
because imperative languages utilize variables, imperative programs have many simple lines
of code for initializing or changing variables.
Moreover, another way to compare these two programming paradigms is their execution
efficiency. Generally, interpreted functional programs are much slower than compiled
imperative ones. However, nowadays most functional languages have their own compilers
so their execution speed is not that much slower than the imperative ones. However, it can
be argued that because functional programs are considerably smaller than imperative ones,
they should run much faster than the imperative programs. Nonetheless, this is not the case,
because the functional lazy evaluation has a negative impact on execution efficiency. The
major downside of lazy evaluation is that it makes very difficult to predict memory usage. For
example, two expressions may achieve the same result but they may need different amount
of memory.
Another execution efficiency difference between the two programming paradigms, which
gives imperative languages an advantage, is that they were designed to run efficiently on
von Neumann architecture, whereas, functional languages are designed based on
mathematical functions. However, functional languages have a greater advantage in
readability. The reason is that every function is designed to achieve a particular task given
its argument, whereas, imperative programs, the details of tackling with variables makes
very difficult to understand the logic of the program.
Finally, it is difficult to design and use concurrent execution in imperative languages, and
sometimes it is very complicated process. Because, in imperative programming, the
programmer needs to make separate concurrent parts of the program and then synchronize
their execution. On the other hand, functional languages divide programs into independent
functions, which have no side effects and their operations do not dependent on any global
variables. Consequently, this makes functional programs easier to be executed concurrently
6
and because functions in functional languages preserve immutability, they do not need to be
synchronized.
3 Summary
Alternatively, functional programs are much easier to reason about and prove that they are
correct, because their dependence on any data structure is explicit. Additionally, functional
languages use simple expressive expressions and emphasis the evaluation of expressions.
Each expression is evaluated independently, which makes functional languages to have no
side effects, which means that independent sub-expressions can be evaluated in any order
or parallel. Moreover, features such as higher-order functions and the lack of side effects
support creating very efficient and reusable programs. Programs can only interact through
their visible interfaces. Therefore, all phases of program development (i.e. prototyping,
debugging and testing) are made less complex.
7
Reference
Bird, R. Walder, P. (1988) Introduction to Functional Programming. Prentice Hall
International.
Chitil, Olaf. (2000) ‘Functional Programming’, Journal of Functional Programming, pp. 14-20.
Gyori, A. Franklin, L. Dig, D. (2004) Cross the Gap from Imperative to Functional
Programming through Refactoring. Oracle, Czech Republic.
Hughes, John. (1989) Why Functional Programming Matters. Computer Journal, 32(2):98–
107.
Van Roy, P. (1990) Can Logic Programming Execute as Fast as Imperative Programming.