One of my great joys when designing things is when I discover that I can lift a restriction and make something both simpler and more powerful at the same time. This can happen at all levels, from something like changing a function signature to make it more generic, right up to unifying high level system components. The more generic something is, the more situations you can use it in, and the more value it can provide.
But there comes a point where something can be too general—
goto statement. Edsger Dijkstra wrote about its dangers
in 1968 in his letter The Go To Statement Considered Harmful, and Donald Knuth wrote
in his 1974 paper Structured Programming with Go To Statements about how the
majority of the dangers can be avoided by adding some restrictions to
As we now all know, there are a handful of control structures that
goto statement was used to simulate which are
perfectly safe and well understood—
return, function calls, etc.
Anything else was usually too complicated and error prone. The
problem with using raw
goto statements was that it
wasn’t always clear which of the good structures the author was
intending to use, and it was easy to make subtle mistakes that went
unnoticed and caused huge problems. And so we all agreed that despite
the fact that a single statement is more general and can do all the
work of the other handful of control structures and more, we’d be
better off without it.
By restricting ourselves to using only well understood control structures, we free ourselves from the possibility of writing error-prone, incomprehensible spaghetti.
It’s worth thinking about whether adding restrictions to other tools
and techniques we use could actually make our lives easier. I think
we are starting to see that even the
for loop is more
trouble than its worth, as more and more languages embrace higher
level, more expressive forms like
reduce. Much of the benefit of
functional programming comes from restricting use of the assignment
operator. Concurrency is another area that I think would benefit from
some restrictions. Programming directly with threads and locks is
incredibly flexible, but it’s also fraught with potential race
conditions, deadlocks and data integrity issues. Restricting
ourselves to well understood abstractions like the actor model
would free us from the hassle of dealing with these problems.