The first programming languages looked like assembly languages. With assembly, you have to tell the computer exactly what it needs to do at every point. You have to tell it which memory slot to store data in and which line of code to go to next.
This is full imperative programming. You have to describe every step you want to execute. Naturally, the first higher-level programming languages were also imperative:
These languages were a little more readable than Assembly, but the paradigm for writing code was the same: the developer had to tell the computer what and how it should execute the logic.
#include <stdio.h>
int main() { for (int i = 1; i <= 5; i++) { printf("%d\n", i); } return 0;}
Then around the 1960s computers started becoming more powerful, and people realized that we could shift some of the cognitive load to the machines. Instead of telling the machine what to do, what if we could just tell it what we want and let the underlying system figure out the steps to get it done?
Thus the declarative paradigm was born. Some of the first declarative languages were:
Instead of telling the machine to loop through each item, and then print each one, we just tell it what we want to print.
(print (mapcar #'(lambda (x) x) '(1 2 3 4 5)))
Most modern general-purpose languages have capabilities of both built-in.
Imperative
Let’s use Dart, one of the most beautiful languages out there, as an example. To write imperative code, you must tell the computer what to do, step-by-step.
Let’s say you want to print all the numbers in an array that are greater than 3. The imperative approach would be to tell the computer what to do at each step of the process.
- First, loop through all the numbers in the list.
- Then, check if each number is greater than 3.
- If it is, add it to the filtered list.
- Finally, print the filtered list.
List<int> numbers = [1, 2, 3, 4, 5];List<int> filtered = [];
for (int number in numbers) { if (number > 3) { filtered.add(number); }}
print(filtered); // [4,5]
Declarative
The declarative approach tells the computer what outcome it wants, and then lets the computer do the cognitive load of figuring out how to do that.
Let’s take the same task of printing numbers greater than 3, but using a declarative approach.
- Print a list of all the numbers from the array that are greater than 3.
List<int> numbers = [1, 2, 3, 4, 5];print(numbers.where((num) => num > 3).toList()); // [4,5]
Usually, a declarative approach will have fewer lines of code, since it’s just telling the computer what outcome you want. The code also reads closer to the English language.
So that’s the key difference between imperative and declarative programming.
- Imperative: Tells the system what to do, step-by-step.
- Declarative: Tells the system what outcome you want.
Modern tech is Declarative
Given the lighter cognitive load necessary to write declarative code, most modern frameworks are referred to as Declarative UI Frameworks.
- React
- SwiftUI
- Flutter
For example, in Flutter, you write the code for the UI using “widgets”, and you declare these widgets in a tree-like structure that corresponds to how you want the app to look. You write what you want to see.
Column( children: [ const Text('Hello, Flutter!'), const SizedBox(height: 16), const Icon(Icons.favorite, color: Colors.pink, size: 48), ElevatedButton( onPressed: () { print('Button pressed!'); }, child: const Text('Click Me'), ), ],),
Previously, you would have to go through each step of the process of creating the component, setting its properties, and then adding it to the view.
// Create root layoutLinearLayout layout = new LinearLayout(this);layout.setOrientation(LinearLayout.VERTICAL);layout.setPadding(50, 50, 50, 50);layout.setBackgroundColor(Color.WHITE);
// Create a TextViewTextView title = new TextView(this);title.setText("Welcome to the Imperative UI!");title.setTextSize(24);layout.addView(title);
// Create a ButtonButton button1 = new Button(this);button1.setText("Click Me!");layout.addView(button1);
// Set click listener for button1button1.setOnClickListener(v -> Toast.makeText(this, "Button 1 clicked!", Toast.LENGTH_SHORT).show());
However, with these newer frameworks, only the UI layer is declarative. A fully declarative language seems unreasonable, since a step-by-step approach is necessary when writing backend logic.
Maybe AI is the ultimate declarative abstraction layer?
If you enjoyed this article and are interested in Flutter, check out this article next.
Get Articles in Your Inbox
Sign up to get the latest articles in your inbox, CEO insights, and free goodies.