Why the imperative examples?

Speaking of example programs: why are so many examples stateful? Wherever algorithms are explained — in textbooks, in academic papers, in websites formal and otherwise — the style of choice is overwhelmingly imperative. Assignment is everywhere; simple maps and folds are written as explicit iteration; data structures are updated destructively for no reason; even recursion is often expressed by loops and state. This is true even in pseudocode, where there's no practical reason not to write functionally. This annoys me. Why can't we write our examples clearly?

Some of this must be simply the inertia of formality. Imperative style used to be the only well-known option, so it's traditional, and when people try to look authoritative by imitating older authorities, they tend to copy their style, even if they wouldn't normally write that way. This happens for writing style, so why shouldn't it happen for programming style too?

Didactic examples also have a good reason to be conservative in the language they use: they're explaining something to someone who doesn't already know it, and may be ignorant of other concepts as well. State and iteration are familiar even to nonprogrammers, while many of the concepts of functional programming are not very widely known even among programmers. So maybe the imperative examples are comprehensible to a larger audience?

And maybe there's a cultural gap: if the people who study (and explain) algorithms have little overlap with those who study how to express them, they may simply be unaccustomed to functional style, and prefer something more familiar. But it seems to me I've seen oddly imperative examples even from people who know better and would never write “real” code that way.

I also suspect that state, especially in small programs, isn't as confusing as we like to think. Little examples don't have the maintenance and modularity problems that large programs do, so maybe state isn't much of a problem for them, and there's not much pressure to write more functionally.

But it still irks me. Is the state of the art, in 2010, to describe algorithms in terms of assignment? Must we communicate new ideas by implementations we would consider unreadable in any other context?

I know there are some people who explain algorithms with functional examples, especially in the Haskell community. But why isn't this the norm?

5 comments:

  1. I'm sure all the reasons you give are right, and probably they're the main reasons. But there's another reason to use imperative style sometimes: as an excuse for introducing lots of variables with instructive names.

    ReplyDelete
  2. I can see how imperative style might serve as an excuse to use more named variables (even though there's no reason not to in functional code). But I doubt descriptive names are a major motivation, because of another common problem with examples: they tend to use inscrutable one-letter names, as if they're trying to look like math rather than code.

    ReplyDelete
  3. examples ... tend to use inscrutable one-letter names

    Ouch. That's appalling. I guess I've been spoiled by the SmallTalk tradition.

    ReplyDelete
  4. Funnily enough, I had originally seen your blog post months ago and couldn't really relate. Until last week, when I re-read the random text generation example in Paul Graham's excellent "ANSI Common Lisp". Graham inexplicably uses a loop with string indexing to get at a word's characters, in order to then destructively write them to a buffer again.

    Maybe this is the easiest way to work with strings in Common Lisp; I'm not CL-savvy enough to answer this. However, I was able to re-implement his algorithm almost purely functionally in Python (which is by no means a showcase for functional idioms) and ended up with shorter, more declarative code. So I can feel your sentiment, Arcane: Why bother writing imperative examples?

    ReplyDelete
  5. If you mean ACL's read-text, that's a reasonable implementation in CL. The obvious functional implementation uses some operations like slurp and re.findall) that CL lacks, so it's easier to use a loop.

    The sort of examples I'm thinking of are those used to explain algorithms, generally in Algol-like pseudocode rather than specific languages. Algorithms textbooks, papers, and references traditionally use this style, even for high-level sketches where there's no reason to compromise clarity.

    ReplyDelete

It's OK to comment on old posts.