Thoughts on Declarative and Imperative Languages

Jakob Kallin | Frontend Thinkful mentor | GitHub

Although front-end development was my introduction to programming and still makes up most of my professional experience, studying computer science at the university has exposed me to many other perspectives on software development. Even for developers who spend all their time in front-end development, looking at the field in a broader context can provide useful insights that ultimately make things easier.

From a theoretical perspective, one interesting question is whether HTML and CSS do in fact count as programming.

HTML is essentially a data format, and writing data files is generally not considered programming, just like writing text in a word processor is not considered programming. That being said, an HTML file, unlike a text document, has specific rules that must be followed for the computer to interpret it properly. Since HTML is extremely forgiving of errors, people who write HTML generally do not have to worry about this, but it’s still very different from using a word processor, so it really falls somewhere between programming and “non-programming”.

CSS, on the other hand, is a different story. It doesn’t look very much like JavaScript, which is a programming language from the extremely widespread imperative paradigm (to which most major languages belong, at least partially). In most imperative languages, the programmer has to spend a lot of time dealing with state (storing and changing data as the program runs) and control flow (the order of operations). CSS doesn’t contain either of those things, and that’s largely because it belongs to the declarative paradigm.

Declarative programming is a form of programming that removes us as much as possible from the low-level details of how things happen; it tries to concern itself only with what happens. An example of this is the fundamentally different ways of handling things like applying effects when the mouse cursor hovers over an element:

  • In JavaScript, we need to first find the element, then we need to add an event listener that specifies what should happen when the cursor hovers over the element. We need to worry about when to add this listener (it cannot be before the element actually exists, and it cannot be much later because we want the hover effect to be available immediately) and we need to make sure that we don’t accidentally add the same listener twice. Both are problematic issues that I have seen many students run into in their projects.
  • In CSS, we simply write: “selector:hover { properties to set }”. We don’t worry about when the listener is added (we assume it to be added as soon as it’s needed) and we don’t risk adding it twice by mistake. In fact, we don’t even need to worry about the concept of a listener to begin with. In essence, we have described what should happen without worrying about exactly how it should happen.

You might ask yourself why we bother with imperative languages if declarative languages are so much more powerful, concise, and easier to use.

The answer is that at this point, we still need access to the flexibility of imperative languages. Designing a declarative language that is powerful enough to completely replace an imperative one is difficult, which is why it has currently only been done in select areas (such as styling an HTML document). Other notable declarative languages are regular expressions (which can be immensely useful for any computer user) and SQL (a database query language).

Performance also plays a role, because making declarative languages fast enough can be a challenge. (It should be noted, though, that well-designed declarative languages can also avoid many common performance issues in imperative languages, so it goes both ways.)

Overall, the programming world in general is certainly moving in a more declarative direction, even though it’s a slow process. Universities put an incredible amount of difficult work into developing techniques and tools that are ultimately intended to make programming easier for developers, often by making use of the declarative paradigm.

When relating all of this theory to your day-to-day work, there are several observations to make:

While there are significant differences between CSS and JavaScript (and other imperative languages), I would definitely call both of them programming. Both of them require a non-ambiguous specification of rules for a computer to follow in order to achieve a specific result. In this case, the result is a web page, and that includes everything from colors and fonts (appearance) to animations and responsiveness (behavior).

The main challenge when going from CSS to imperative languages is getting into the imperative mindset, where state and control flow are challenging and problematic concepts that we are spared from in CSS. Whether you are picking out HTML elements by traversing a DOM tree (imperative) or writing a selector (declarative), it’s still an act of programming because you are giving a specific, non-ambiguous command for the computer to follow. (In fact, most developers nowadays use CSS selectors with jQuery in order to select HTML elements, which is an example of declarative programming creeping into an imperative language.)

If you are a beginning developer expanding from HTML and CSS to JavaScript, the imperative nature of the language will certainly be a challenge, but it’s useful to keep in mind that what you are doing is still programming, and much of it can be related back to things that you have already learned in CSS, such as the example with hover effects. When nasty bugs get you down, it’s also useful to keep in mind that imperative programming is difficult enough that even experienced developers look for declarative alternatives - and that these alternatives are becoming more sophisticated and widespread every year.

Another way of putting it is that we may well see JavaScript gradually becoming less crucial to web development, in favor of CSS and other declarative languages that have yet to even be designed. It’s difficult to find a bigger fan of JavaScript than me, yet even I would be thrilled if it were eventually replaced with declarative alternatives allowing us to focus on what to do rather than how to do it.