what makes a language declarative or imperative?(see, in chronological order, William Cook, Bob Harper, and Neel Krishnaswami). Trying to get a crisp definition of vague terms often involves endlessly going around circles. Just in case that isn't bad enough, in this specific case, some believe that their favourite term connotes superiority, thus setting otherwise reasonable people against each other. Intuitively, the two terms are talking about the level of abstraction of a programming language: declarative means that something provides more
whatand less
how; while imperative is more
howand only implicitly
what. We have a vague feeling that the terms should be precise opposites, but in practice we keep stumbling across examples which are hard to fit precisely into exactly one of the terms. William and Bob are, I believe, both correct in saying that, if the terms declarative or imperative once had a specific meaning, they have long been robbed of it.
I would suggest that what's really going on is that we're trying to use
the terms to express absolutes when they can only meaningfully express the
relative relation of one thing to another. Before tackling the original point
directly, let me try and give an example that is less likely to offend those
of us immersed in programming languages. Imagine there are two people
competing against each other in a 4km cycle race. Jim takes 5 minutes and Tim
takes 4 minutes 50. We might say Tim is quick
but we would be
incorrect. Tim is only quick relative to Jim. When Kim — who
can do the race in 4 minutes 30 — comes into the room, we can clearly see
that Tim is not quick compared to Kim. Thus, while relative comparisons
between individuals are safe, absolute statements are not: we can't be sure
if we will encounter a person who changes our notions of quickest
or
slowest
. Put more carefully, the absolute statements are only correct
for the set of individuals we've sampled. Relative statements (e.g. Tim is
quicker than Jim
) remain correct even when we encounter new individuals.
With that in mind, let's look at a few examples from programming languages:
- Absolute:
Haskell is a declarative language
. Incorrect. - Relative:
Haskell is a more declarative language than C
. Correct. - Absolute:
C is an imperative language
. Incorrect. - Relative:
C is a more imperative language than Haskell
. Correct.
Depending on your background, you may find the two incorrects hard to swallow initially. Consider this little C fragment:
a = 1; b = 2; c = 3; d = a + b + c; print_int(d);and an example compilation of it into ARM assembler [1]:
MOV R0, #1 MOV R1, #2 MOV R2, #3 ADD R3, R0, R1 ADD R3, R3, R2 STMDB R13!, {R0} MOV R0, R3 BL print_int LDMIA R13!, {R0}
Both fragments behave the same, in the sense that they describe the same
output (the printing of the number 6). The C version however states much less
detail about how that output should occur. The assembler version first has to
break the addition down into 2 separate instructions. It then has to save the
original value of R0
to prevent it being clobbered by the
argument being passed to print
. Relative to C, the assembler
version feels much less declarative
: one might even be moved to say
that the assembler version is more imperative
.
The fun begins when one realises that the assembly version is not the end
of the road. We could, if we wished, go all the way down to electrons when
considering a program executing. In the opposite direction, a DSL for
expressing Context Free Grammars may feel much more declarative
than
the Haskell program that is generated from it. As that might suggest, we also
need to bear in mind that there isn't a strict hierarchy here. There are
multiple dimensions in which different languages can be considered
declarative
or imperative
relative to each other.
This has an interesting implication. For any given two abstraction levels, we can find another in between, or one sideways (and so on). If we wanted to name each, we'd go mad. Thus, proposals such as Neel Krishnaswami's are interesting thought exercises, but we simply can't scale them up (unless you find the prospect of a massive, ever-expanding dictionary appealing).
In summary, trying to define declarative and imperative
precisely as absolute terms will never work, if it ever did. Using them as
relative terms can feel pedantic, but at least has the virtue of not being
inaccurate. Although we really only need one of imperative or
declarative, I expect both terms to comfortably outlive me, and for
people to use them as vague absolutes in the same way that we use
quick
and slow
as vague absolutes. It's also worth noting that the
programming language community is not the only one bedevilled by this issue.
The UML folk tie themselves in knots over Platform Independent and Platform
Specific Models (PIMs and PSMs). Students of war have spent hundreds of years
trying to nail down perfect definitions of strategy and tactics, without
success. Humans like the seeming certainty of absolute statements, even in
cases where only relative comparisons are safe.
Acknowledgements: My thanks to Carl Friedrich Bolz and Edd Barrett for insightful comments on early drafts of this article. All opinions, errors, omissions, or infelicities, are my own.