Understanding Imperative vs Declarative Programming
You might have heard these terms being tossed around a bit, especially when it comes to things like React. React is declarative according to the documentation, but what does that really mean? Let's take a look at the difference between these two paradigms.
What is Imperative Programming?
According to our good friend Wikipedia, we have the following definition:
In computer science, imperative programming is a programming paradigm that uses statements that change a program's state.
In essence, this means we are issuing instructions describing both what and how we want the computer to perform its task. Imperative programming makes use of relatively low-level function and API calls to have more absolute control over the implementation details of how something is done.
An example of some imperative code is the following JavaScript:
const domNode = document.getElementById('foo');
domNode.style.color = 'red';
Here, we are telling the browser how to get a certain element, and how to change its color to red. What, and how.
What about Declarative Programming?
By contrast, declarative programming is a higher-level concept. We tell the system what to do, but not strictly how to do it. The implementation details are abstracted away from us, but they are still there. Make no mistake, you can't tell a computer what to do without something telling it how to do it, somewhere down the chain.
A simple example of declarative programming is the following HTML:
<div>
<h1 id="foo">My Heading</h1>
</div>
We are telling the browser what we want it to do, but the actual implementation of how it interprets that HTML and renders it to our screen is abstracted away, and out of our hands.
React is Declarative
So when people say React as declarative, what does this mean for us? If you think about it, it makes sense. React shares a lot of similarities with HTML, and the way things used to be done. We can build entire, complex applications without ever having to do direct DOM manipulation for the most part. Sure, there are still some edge-cases where directly touching the DOM and using refs is the best approach, but those cases are few and far between.
Most of the time when writing code for React, you will be composing your applications by nesting components within each other. Some of these components will contain business logic, but even then, chances are you will seldom write imperative code.
Consider the follow React code:
const foo = () => {
return <h1 style={{ color: 'red' }}>My Heading</h1>;
}
Here, we are telling react to make this component and give it red text, but the actual imperative calls under the hood to make this happen are not our concern. We tell React what to do, and it figures out how.
Other examples of Declarative Coding
Domain-Specific Languages (DSLs) are very often Declarative in nature. This is because the point of a DSL is to provide an interface where the available instructions make sense in the context of the domain. Consider SQL, a DSL for interacting with and querying databases. We could have some SQL like:
SELECT * FROM `users` WHERE `users.date_of_birth` IS NULL;
Here we are telling the database "get me all the users with a null "date of birth" field", and because the DSL is so finely tuned, it almost reads like plain English (although the same cannot be said for some more advanced queries).
The important thing here is that we told the database what to do, and the engineers who implemented the DSL on the backend have done the hard work of figuring out how to do it.
Depending on the situation there is always going to be a need for both declarative and imperative coding. Don't make the mistake of thinking you need to pick one and stick to it. Understanding the differences between these two paradigms, and how they come together is the first step in knowing when and where to use each.