Goto and the folly of dogma

Many programmers are surprised to find out that the goto statement is still widely used in modern, high-quality codebases. Here are some examples, using the first codebases that come to mind:

Repo goto usages ratio to continue
Linux kernel 150k 6.27
.net CLR 5k 2.13
git 960 0.76
Python runtime 5k 16.9
Redis 554 2.14

The ratio to usages of the continue keyword is provided to normalize for lines of code and the prevalence of loops in the code. This is not limited to C code bases. for example has 1,511 goto usages and a ratio of 3 goto usages to each continue usage. The C# compiler, written itself in C#, clocks in at 297 goto usages and 0.22 ratio.

People who take “goto is evil” as dogma will point out that each of these usages could be rewritten as gotoless alternatives. And that’s true, of course. But it will come at a price: duplication of code, introduction of flags, several if statements, and overall added complexity. These are highly reviewed codebases written by talented people. When they use goto, it’s because they find it to be the simplest approach.

This is exactly how dogma hurts software development. We take a sensible rule that works most of the time and promote it to sacred edict, deeming violators as inferior programmers, producers of unclean code. Thus something that would have been a helpful guideline becomes a hard constraint. Pile up enough of these, and code that could have been simple ends up in a tangled mess, all in the name of “purity.”

We have a long tradition of dogmas, but goto is the seminal example, denounced in Edsger Dijkstra’s famous letter, Go To Statement Considered Harmful. Just barely over a page, it’s a good case study. The letter is good advice in the vast majority of cases: misuse of goto will quickly land you in a maze of twisty little passages, all alike. Less helpful were the creation of a social taboo (goto is the province of inferior programmers) and the absolutist calls for abolition. Dijkstra himself came to regret how “others were making a religion” out of his position, as quoted in Donald Knuth’s more level-headed paper, Structured Programming with go to Statements.

Taboos tend to accrete over time. For example, overzealous object-oriented design has produced a lot of lasagna code (too many layers) and a tendency towards overly complex designs. Chasing semantic markup purity, we sometimes resorted to hideous and even unreliable CSS hacks when much simpler solutions were available in HTML. Now, with microservices, people sometimes break up a trivial app into a hard-to-follow spiderweb of components. Again, these are cases of people taking a valuable guideline for an end in itself. Always keep a hard-nosed pragmatic aim at the real goals: simplicity, clarity, generality.

When Linus Torvalds started the Linux kernel in 1991, the dogma was that “monolithic” kernels were obsolete and that microkernels, a message-passing alternative analogous to microservices, were the only way to build a new OS. GNU had been working on microkernel designs since 1986. Torvalds, a pragmatist if there was ever one, tossed out this orthodoxy to build Linux using the much simpler monolithic design. Seems to have worked out.

Every programmer pays lip service to simplicity. But when push comes to shove, most will readily give up simplicity to satisfy dogma. We should be willing to break generic rules when the circumstances call for it. Keep it simple.