16. Structured Programming

All imperative languages look much the same. Even if you don't know a language, or its exact syntax, you can look at the code and have a pretty good idea what it's doing. There's a reason for this: all coding is now done in a style called structured programming.

The first programs were written in machine code (lines of 0s and 1s) and then later in assembler (text or mnemonic versions of machine code e.g. add A,B). Program flow (the instruction executed next, if not the next instruction in the program) was controlled by jump instructions. When higher level languages arrived, the jump instruction was implemented by the goto instruction. Control flow by goto lead to unreadable and undebuggable code: code would leap from one page of your program to another and back again. It didn't always go where you expected and it was difficult to write large programs. The control flow problem was fixed by Edsger Dijkstra who building on the work of others wrote the seminar paper

Dijkstra, E. W. (March 1968). "Letters to the editor: go to statement considered harmful". Communications of the ACM 11 (3): 147148. doi:10.1145/362929.362947. ISSN 0001-0782. (EWD215).

Although it took many years, Dijkstra's views were eventually accepted by all, computer languages were rewritten to remove the goto statement, and students (and programming languages) were changed over to structured programming.

Dijkstra realised that not only is programming difficult, but that it's difficult to accurately specify a programming task.

from wikipedia: "Dijkstra was known for his essays on programming; he was the first to make the claim that programming is so inherently difficult and complex that programmers need to harness every trick and abstraction possible in hopes of managing the complexity of it successfully." and "He is famed for coining the popular programming phrase '2 or more, use a for', alluding to the fact that when you find yourself processing more than one instance of a data structure, it is time to encapsulate that logic inside a loop."

As a corollary of Dijkstra's first statement: English is a sufficiently ambiguous or imprecise language that for a large enough program, it will not be possible to unambiguously specify its requirements in English. This accounts for overruns and non-working code in large applications: for examples see Software's Cronic Crisis (start with the Loral disaster). Although computer programmers are mathematically trained and computer code has to be mathematically precise, the customer is usually represented by the people and who are not mathematically trained. As a result, English (rather than mathematics) is used to specify the function of software. Any large software project specified in English is doomed from the start.

The only attempt to make a rigorous language based on English is legalese. Neither programmers nor their customers understand legal English.

Although much effort has gone into mathematically precise specification languages, there are no working examples in the software world. Instead programmers have moved towards writing software, where the functions and interfaces to their code is explicitly stated. This is called Design by Contract (http://en.wikipedia.org/wiki/Design_by_contract) and started with Hoare Logic (http://en.wikipedia.org/wiki/Hoare_logic).

As a result of Dijkstra's work, (from Structured Programming http://en.wikipedia.org/wiki/Structured_programming) accepted control contructs are

Because of the design of modern computer languages, it is difficult, if not impossible, to write unstructured programs. While I'll happily give you examples with syntax errors, and expect you to figure your way out of them, I will not be giving you examples of badly structured programs, or send you on wild goose chases looking for errors in the structure of the code. These may be impossible to write (and have run).

OK, here's an example of a badly constructed piece of structure programming. In poorly designed code, you may have trouble setting up variables before entering a block so that they can be handled without intervention inside the block. Conditions have to be anticipated before entering the block - i.e. you can't handle a condition by exiting the block of code. Structured programming says that you still have to let the code block continue execution. If you don't grasp structured programming, you will not understand that code is required to exit at the end of the block, and you will try to exit in the middle. If you're stymied trying to write a block of conditionals, think whether you're allowing the code to exit at the bottom no matter what happens in the middle.

In structured programming you aren't allowed to do this

set_of_numbers=[1,2,3,4....n]
#non-structured code
for n in set_of_numbers:
	if isprime(n):
		print "found prime number %d", n
		exit
	else:
		print "non-prime number %d", n

#following statements

(In fact python, and many other languages allow you to do this, despite it being bad practice.)

A structured programming way of doing this, which anticipates finding a prime, would be

set_of_numbers=[1,2,3,4..n]
#structured code
n = set_of_numbers.pop()	#remove the top number off the list
while (!isprime(n)):
	print "non-prime number %d", n
	n = set_of_numbers.pop()

print "prime number %d", n

There may be circumstances in which you have to use the non-structured format (I've done it with multipli-nested loops, where you had to break out of an inner loop - it's possible I didn't need to do this), but if you can use the structured format, do so.

Student question: One of the two following pieces of code (modified from temperature_controller.py) is standard structured code; the other shoddy code that's not really structured, but is accepted in many languages (including python). Which piece of code is which and what's the problem?

#!/usr/bin/python

def check_temperature(t):
	if (t > 80):
		result = 1
	elif (t <= 60):
		result = -1
	else:
		result = 0 

	return result

#main
temp = 61
print "the temperature is %d." % temp,
print check_temperature(temp)
#---------------------

#!/usr/bin/python

def check_temperature(t):
	if (t > 80):
		return 1
	elif (t <= 60):
		return -1
	else:
		return 0

#main
temp = 61
print "the temperature is %d." % temp,
print check_temperature(temp)

#---------------------
[112]

How will the non-structured code get you into hot water? Maintenance. If later you come back and don't spend the time to find all the exit points, you might add this line at the end of the if/else block.

print "the temperature is %d." %t

In the non-structured code, it won't run. Do you want to be flying in a plane, whose guidance system has been written in non-structured code? As well code checking programs (which are used in a big project), will see in main() that check_temperature() returns something printable, but that the definition of check_temperature() doesn't.



[112]

The problem in the 2nd lot of code is that there are multiple exit points from the if/else block.