Declarative vs Imperative Programming
Azhar Mohammad
Fractional CTO | Founder @ Truscable - Enterprise Grade Technology, Startup Agility
Declarative and Imperative are programming styles, the former allows you to declare the "What" and the latter is about defining the "How".
Before we go any further, let's describe with a simple example, what declarative programming is. The best example that comes to my mind is HTML. If you need to create a simple "hello world" HTML, you can write an HTML, which just specifies "how the page is supposed to look". This is then interpreted by the rendering engine in a browser to create a DOM (a tree of objects used by the browser to interpret, render and provide interactivity) and render on to the screen. For instance:
<!DOCTYPE html
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>>
The above HTML is an example of using a declarative style where the output is declared in the form of an HTML to be interpreted by the rendering engine.
Let us take a look at the equivalent imperative style using Javascript.
// create a new h1 elemen
var heading = document.createElement("h1");
// set the text inside the h1 element to "Hello World!"
var heading_text = document.createTextNode("Hello World!");
heading.appendChild(heading_text);
// create a new body element and append the h1 element to it
var body = document.createElement("body");
body.appendChild(heading);
// create a new html element and append the body element to it
var html = document.createElement("html");
html.appendChild(body);
// set the document's root element to be the html element
document.documentElement.replaceChild(html, document.documentElement);t
That was a lot of work, just to create a hello world page! Can you imagine the amount of work it would take to render complex components used in modern day applications, not to mention the complexity of dynamic state changes to the HTML elements?
The difference between both the approaches is that in the declarative approach, the template (What) is declared and the browser takes care of the underlying logic of arranging the DOM nodes and presenting this information (How). In the second approach, each and every DOM element definition is described (How) and executed which would then get interpreted and rendered by the browser.
Let's compare the 2 approaches using a simple example. If I have an array of names
const names = ['Alice', 'Bob', 'Charlie', 'Alex']
?and I would like to get all names that start with the letter 'A', following is an imperative approach:
?const filteredNames = []
for (let i=0; i < names.length; i++) {
??if (names[i].toLowerCase().startsWith('a')) {
?? filteredNames.push(names[i]);
??}
};
The same can be done using a declarative approach with the following:
const filteredNames = names.filter(name => name.toLowerCase().startsWith('a'))
The difference between the imperative and declarative styles in the above examples is that in the declarative style, I only supply the logic necessary to filter out the elements and let the in built method take care of the rest whereas in the imperative style, I decide how to iterate over the array and maintain a variable to hold values apart from the comparison logic.
Object Oriented languages can be declarative too!
Often times when looking up declarative and imperative programming, we get content that classifies object oriented languages as imperative and functional programming languages as declarative highlighting the support for higher order functions. While it is true that HOF's are declarative, it is worth noting that they are not the only way to do declarative style of programming. Even without them, Object Oriented languages such as Java have been supporting a declarative approach.
Let's take the example of Java for sorting an array of items. Let's assume the situation prior to SE 8, when lambda expressions were not available.
We have the java.util.Comparator interface which could be implemented for sorting. The comparator interface just requires a user to implement the logic to decide which value is greater, given 2 values.
Example: We want to sort a list of Person objects first by age, and then by name if the ages are equal.
领英推荐
Declarative Approach
import java.util.Comparator
public class PersonComparator implements Comparator<Person> {
??@Override
??public int compare(Person p1, Person p2) {
????// Compare ages
????int ageDiff = p1.getAge() - p2.getAge();
????if (ageDiff != 0) {
??????return ageDiff;
????}
????// If ages are equal, compare names
????return p1.getName().compareTo(p2.getName());
??}
}
List<Person> people = new ArrayList<>()
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 20));
Collections.sort(people, new PersonComparator());
for (Person p : people) {
??System.out.println(p.getName() + " " + p.getAge());
}
Output:
Charlie 20
Alice 25
Bob 25
The above is an example of a declarative approach, since we are only defining the comparison logic in a 'compare' method and the sorting logic is actually taken care of by the inbuilt Collections.sort method.
The same can be written by implementing 2 nested for loops and iterating over each element with a complexity of O(n^2) using bubble sort. That would be an imperative approach. Please note that we could also implement more efficient algorithms, however that is not the point of this example. The point is that the sorting logic itself has to be implemented apart from the comparison logic and the logic to sort which boils down to standard sorting algorithms, can be externalised if using a declarative approach.
It promotes reuse of tried and tested libraries and frameworks, rather than re-inventing the wheel!
I hope with the above examples, we have a clear understanding of the difference between declarative and imperative programming.
A few more examples of declarative programming are listed below:
1. Front end frameworks such as React, Vue and Angular promote declarative programming by providing ways to define templates and adding interactivity via hooks, derived state,?watchers, handlers. They abstract away a lot of complexity and provide a way to declare functions in order to manage state. You are expected to declare a template and modify the state. The "How" of managing reactivity as well as DOM updates is the framework's responsibility. Contrast this with something like JQuery which would expect you to provide exactly what has to be manipulated.
2. Frameworks that allow you to declare. Dependency injection is another example of a declarative approach where the approach to injecting a dependency is implemented by the framework and the dependency is declared.
3. SQL - provides a structure for querying data, but does not define the exact steps on how to retreive the data. You would provide the different tables and the relationships between them and in between the fields, however never the steps involved in retreiving the data.
Pros:
Cons:
Finally, I would like to conclude with the following thought:
"Is Declarative style really a programming paradigm or should it be thought of as a design pattern that should be incorporated wherever it makes sense?"