The Freedom of Restrictions

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—where it permits far too wide a range of uses, and it starts to cause more problems than it solves. One famous example of this is the 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 its usage.

As we now all know, there are a handful of control structures that the goto statement was used to simulate which are perfectly safe and well understood—if, switch, for, while, break, 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 map, filter and 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.