Imperative and Declarative Paradigms

Learn about programming paradigms and their differences.

What are paradigms?

Paradigms are different ideas to solve a problem; they are the thought behind the code. In a real situation, where we might have multiple ideas of how to get to an answer, the paradigm would be the approach that we chose to solve a problem.

Moreover, relating them to programming, paradigms are normally used to create a programming language, which uses the concepts and ideas defined by the paradigm when implemented. Sometimes, more than one paradigm is used to create a language.

We have a large number of paradigms, which are distributed across the major ideas of imperative and declarative programming. These paradigms lead to establishing the rules and logic to develop programs.

Press + to interact
Examples of imperative vs. declarative paradigms
Examples of imperative vs. declarative paradigms

Imperative paradigm

Imperative paradigm programming languages are the most used and taught programming languages nowadays, even though there’s a significant increase in the popularity of declarative programming. This is one of the oldest programming paradigms, and its main focus is on how to achieve the goal.

The main characteristic of the imperative paradigm is the definition of sequences of instructions representing modifications in the states of a system. It features a close relation to Von Neumann’s architecture, the computer architecture that most of our computers use—a memory unit, an arithmetic logic unit (ALU), and a control unit (CU). 

It has two derived paradigms that got really famous:

Examples of Famous Imperative Paradigms





Subdivides the system into collections of subroutines with particular instructions, structures, and variables

BASIC, C, Pascal, and Python

Object oriented

Represents logical sequential thinking that’s suitable to our understanding; uses modular organization with classes, attributes, methods, and objects

Java, Python, and C++

Declarative paradigm

The main focus of the declarative paradigm is what to do, guiding the systems with what they should accomplish regardless of how to perform the tasks to get there. So the process is irrelevant as long as we achieve the objective. Due to this characteristic, the implementation of languages that follow this paradigm has a higher abstraction level, which improves the maintainability of a program. This is a consequence of using predetermined command structures to define tasks.

There are only three derivations—logic, database, and functional.

Declarative Paradigms





Uses formal logic to solve problems, relying on a knowledge base with several facts and rules to answer queries;

solves logical problems like puzzles and series 

Active Server Pages (ASP), Datalog, and Prolog


Based on data and its movement; used in databases themselves



Programs are a composition of functions, which are executions of a series of mathematical functions

Clojure, Lisp, Perl, and Haskell

Choosing the right paradigm

After talking so much about these two groups of paradigms, it would be reasonable to assume that they look pretty good and will lead us to the same conclusion, just taking different paths. However, it’s really important to know when to choose each paradigm because depending on the problem we have, there might be a better option.

So, it’s important to know the pros and cons for each group.

Comparing the Two Groups of Paradigms





  • Objective code in which we don't need lots of abstractions to implement a solution
  • Easier for different teams to work on distinct stages of a software lifecycle, such as development and maintenance, due to abstraction level
  • Minimizes data mutability, which improves program security and test coverage
  • Might use methods not yet known at the time of programming, which is quite good for maintenance
  • Sometimes hard to understand for external people
  • Conceptual model; thinking in terms of solution states contradicts natural human thought processes


  • Very simple to learn and implement
  • Conceptual model approach is very easy for beginners to understand
  • Contains clear ideas of iterating over collections (loops)
  • Has the concept of variables, similar to what we learn in mathematics

  • Complex problems might be very hard to solve, especially when considering the rise in algorithmic complexity, as indicated by Big O notation
  • Less productive; as in the majority of the languages, they tend to be more verbose
  • Higher risk of errors when editing
  • Harder to have full test coverage because we might lose control of the state during the system, and it’s really hard to do tests that will cover the software as a whole
  • Difficult in debugging for the same reason that it’s really hard to test

All these pros and cons might require further explanations, particularly since they should be considered within the context of a specific problem, helping us determine the most suitable choice. Nevertheless, these are common scenarios that might be applied to a great majority of problems.

Functional paradigm

The functional paradigm is the one that we’ll be taking a closer look at. We’ll do a deep dive into all its concepts and guidelines in the next lesson, but here we’ll describe a bit more about the approach and its history.

All functional programming (FP) languages are based on a simple and elegant mathematical foundation, Lambda Calculus. Lambda Calculus is a universal computational model based on mathematical functions and function composition.

This paradigm was first implemented in 1950. Lisp was the first functional programming language. It was created to handle lists, introducing the idea of treating code as data and using a very unique dialect, which is still used to this day.

Even though the functional paradigm is old, its usage has been mostly related to the academic world. This is because academia and industry have different styles of thinking. Plus, it’s more challenging to set up an environment that’s able to run functional paradigm languages.

This stagnation lasted many years, until new functional programming languages, with advanced features to make functional programming practical, emerged, such as ML and Haskell. These features included static type systems, polymorphism, type inference, algebraic data type, pattern matching, and lazy evaluation. After that, it started getting traction again.