Structured Programming
09 March 2016Back in 1968 Edsger W. Dijkstra wrote an open letter named "Go To Statement Considered Harmful". As already suggested from
the title, the very idea was to raise consciousness that the goto
statement is more harmful then helpful. From
today view we would expect that this idea catches fire really fast, but it didn't. It took quite a long time. Even during
all the 1970s and 1980s that question was debated a lot.
Looking back at it there are some interesting questions that is worth to look at. The first one was, if goto
was
harmful, what was the alternative to goto
? And why exactly is goto
harmful, and why exactly is the alternative better?
I think that looking at this questions and their answers is still a very important step forward in understanding programming and raise the awareness on how we achieve a more clean way of coding.
Why "goto" was considered harmful
At first we have to understand the time in which these statement was published. It was a time in that nearly every programmer
actually used a language with such a control statement. Not only that, it usually often was the only way to provide any
kind of control structures. There were no "subroutines", no if
, while
, or for
loops. No blocks of code ans so one. Sure
there existed languages that provides this kind of style of programming. The ALGOL 58 and ALGOL 60 (1958 and 1960) already
provided those kind of structures, but those languages were not used by the large.
Most of the programmers still used languages where a goto
statement dominated. And where the flow of a program was dominated
by direct goto
statements. Dijkstra that was a huge proponent of the ALGOL language coined the term Structured Programming
as an alternative to the goto
keyword, the idea was that we should have explicit control flow. Mainly a language should be separated
into Control Structures, Subroutines and Blocks. Control Structures should be further divided into sequence, selection,
iteration and recursion statements.
But why should we do something like that? The reason was that we anyway had this concepts, but implicitly. All of these ideas
was emulated with the goto
statement. You wanted a for
loop? No problem just jump with goto
to some earlier point.
You wanted a subroutine? You pushed some values onto the stack, jumped to a certain point (your subroutine entry) and that
subroutine poped the right amount of values from a stack. That is still how functions are implemented in today's language.
That is the very reason of why you can get a StackOverflowException
if your language don't support tail-recursion.
But by giving all of them direct labels we give all of our programs more structure. And this structure helps us in understanding
our programs. Or in other words the idea was that we should eliminate powerful construct like goto
and yet use a lot more
weaker but specific constructs.
Structured Programming
That overall leads to another important realization. Nearly all programming languages that we use today are basically some kind of Structured Programming. Whether we are talking about object-oriented language, functional languages or other paradigms.
All of those languages usually provide some kind of control structures, in the form of looping while
, for
or foreach
. Subroutines
in the form of procedures, functions, (static) methods or however your language names them. Selection in the form of
if
, switch
or pattern matching.
It is important to realize this, because you don't really need any of those if you have a goto statement. The goto statement could implement all of those structures just through the use of goto. That is also the reason why i said at the beginning that Structured Programming is still a very important idea up to the current days.
But looking more deeply into it, you will probably ask. Well is that really so? Especially if you use a functional language
you will encounter that looping constructs are discouraged. Even in object-oriented language it is more and more discouraged.
Instead of typical while
or foreach
loops in C# for example you will use LINQ, Java 8 introduced Stream as a more declarative
alternative.
And yet Structured Programming is even more an important topic. The thing is. All those functional interfaces itself or LINQ or Stream
are basically Structured Programming brought to an extreme. Because the important point of Structured programming was not
the introduction of if
, while
, for
, functions or blocks. The important idea was the general concept of eliminating
something powerful and provide more declarative and specific control structures instead.
Powerful vs. Specific
So let's reconsider, why was goto
harmful? goto
was a very powerful concept. It was so powerful that we basically don't need
any concepts of looping constructs, functions and so on. The problem that it raised was that we ended up with programs that was
hard to maintain. Without words that describe specific problems we have problems to face growing programs and we as humans
have problems understanding what happens.
With the introduction of if
, while
, for
, functions and so on we introduced specific concepts that are all possible to express
with goto. But giving them proper names we have it more easy to follow and understand the intention of our code. It is more
easier because every control structure was build for one specific task.
But when we look at the looping constructs we basically see the same things happen. Why do we consider while
, foreach
and so
on more and more harmful these days, and replace them with functional interfaces instead? Because those concepts are still to
powerful. For example what does a foreach
really express? Actually not much. It just describes a go through all data. That is
a general purpose way. But what can you do with it? Well a lot of powerful things!
For example you can can loop with foreach
through an array to find the smallest element or the biggest element. You can apply a function
to every element and change every element, or insert the applied element into a new array. You can filter an array by some condition.
You can loop through two arrays, combine them in various ways, do some calculations with every element and so on. Or in other words.
We can do a lot with such a simple constructs. foreach
is actually the same kind of a powerful concept like goto
.
And that is why we view them as harmful.
Looking at functional interface, they really brought the concept of Structured Programming even further. Instead of just looping we now
have even further separated the idea of looping. We have List.min
, List.max
, List.map
, List.filter
, List.map2
, List.zip
, ...
and so one just to name a view. All of those constructs are still basically just looping constructs. But they are specialized looping
constructs that just do one specific thing.
So having powerful things is bad?
If we follow this thinking then it can lead to the idea that a programming language itself should not have any powerful concepts at all. The less powerful a language is, the better. But actually it cannot be further from the truth. In fact it is quite the opposite, a language absolute must provide as much powerful things as possible.
The reason for that is that we need those powerful concepts to build our less powerful, more specific things. And in building more of those constructs we achieve a better more clean code. A result of this is also that code will be shorter, easier to understand with less bugs.
So we should aim for powerful constructs, and a language should provide those powerful constructs. But we should use them to build all our more specific less powerful constructs. Or in other words, in programming we always should prefer the least powerful concept to implement something.
Sure you can implement filtering a List
with a foreach
loop. Go through every element, push it into a new List
based on some condition.
But why not abstract such a common task? List.filter
does exactly that. It is less powerful, because it just can filter, nothing more,
but we only need to provide the logic for filtering. We have less code after we have a construct like List.filter
. The intention is more clearer.
Reading a List.filter
is easier as to basically try to understand filtering through a series of commands expressed within a foreach
loop.
Using the least powerful thing
When we follow these rule and thinking what Structured Programming is about, I think it leads to more readable code with all of
the benefit this usually have. Like higher maintainability, less bugs, in general less code because of reusable constructs. The
only thing we have todo is to identify our powerful constructs and try to come up with some alternative. In C# the usage of
while
, for
or foreach
is such a thing. In F# besides using looping constructs itself also using direct recursion or using
fold
counts as powerful. Recursion is basically just looping, and fold is the abstraction of tail-recursive looping with
an accumulator. Watch out for them and either try to replace them with more specific constructs. Or build your own control
structs!