Programming For The Terrified Part One

Programming Theory

They say that programmers do not think the same way as other people; that the synapses in their brains are wired-up differently to allow them to progress through tangles of possible outcomes to find the logical pathways.
I don’t know how true this might be, but I recall clearly the first moment I began to think like a programmer, and the epiphany was j = j + 1.
I can’t recall the problem – it was part of a computer science course I was taking and pulling my hair out over – but the solution required iteration through a set of inputs. I’d written a convoluted mess of code to accomplish the end result, but it wasn’t satisfying my instinctive need to have a job well done.
Then, suddenly, the variable presented itself, if not in a blinding flash of light, then certainly in a glow of understanding, and I realised all at once that logical, simple, and even beautiful, solutions to every problem already existed. All I had to do was think them.

If you’ve never written a piece of code – the term for the human-understandable instructions which the computer processes to perform certain actions – or are still in the hair-pulling stage of learning to program, then this is for you.

Computers, unlike a great many people, only speak one language. The alphabet that makes up this language is extremely simple as it only consists of the two states a switch can be in at any point in time – on or off. That’s it. But just as an alphabet of 26 letters can make up thousands of possible words, the two states can be combined in a number of different ways to create a whole series of instructions, which, at the hardware level, can be acted upon in super-fast time by the computer’s processor.

On a virtual level just above the switch state, on and off are represented as 0 and 1, a language known as binary. It is this language which scientists hoping to contact alien life forms use as an indicator of our presence in the universe, because any sentient being which has reached a level of intelligence similar, or surpassing, our own, will be able to understand it.

So, human beings are quite capable of speaking to the computer in its own, simplistic language, but to do so requires a time-consuming process that is prone to a high level of error. In binary, using only 4 bits – and keep in mind that your average computer nowadays has a 32 bit processor – the number one is represented as :
0001

Simple enough. Now let’s look at the number thirteen (it’s my lucky number, I’m Pagan).
0111

If you’re unfamiliar with binary code, this might not appear as intuitive as you first thought. This is because binary is a Base-2 numeric system, and you’ll be used to working with Base-10 in the decimal system we use everyday. The easiest way to understand a Base-2 system is to compare it with the familiar Base-10. So, let’s take that lucky thirteen and do just that.

Base-10 : 10(3) 10(2) 10(1) 10(0)
13 – 0 0 1 3

Base-2 : 2(3) 2(2) 2(1) 2(0)
1101 – 1 1 0 1

As you can see, what we commonly know as the “units”, “tens”, “hundreds” and “thousands” in our decimal system are actually representations of the number 10 to a certain power. The binary system uses the number 2 as the base for exponential calculations in the same way. So, 2 to the power of zero is 1, 2 to the power of one is 2, 2 to the power of two is 3 is 4, and 2 to the power of three is 8, and so on. In the same way that we know the 1 in 13, represented in the decimal system, actually stands for ten we can understanding the meaning of the binary number as :

1 1 0 1

Don’t worry if this seems a little weird right now. As programmers we are capable of coding directly in binary, but there are much easier and less error-prone ways of talking to machines than this that we are going to use. For now, it’s enough that you are aware of the binary system, and that other number systems exist beyond the Base-10 system we use everyday.

How To Make a Computer Cross The Road

No matter which programming language you use, the basic toolkit you need to construct working code remains the same. Once you have learned to program, all you are need to learn, and effectively use, a new language is an understanding of its specialist features, a good reference manual, and hands-on experience – preferably under pressure to produce results. There’s nothing like a looming deadline to kick the old brain cells into top gear.

Programming is all about creating structure out of chaos, logic out of ideals, and the basic building blocks of any programming language are a reflection of this. Since the computer only understands a limited set of instructions, we must restrict ourselves to a form of communication with it that is very simple and highly structured. Computers do not comprehend abstract thought. If you tell a child to “go and play in the traffic”, it’s more than likely he realises that you’re irritated with him and that he’d better behave himself for a while. Tell a computer the same thing and you’d better have insurance, because it’s going to end up as a mangled mess of circuitry and wires under the wheels of a truck.

What then are these tools we need to construct a set of instructions that our computer can understand? First off, we have to be able to ensure that a certain action is performed under a particular set of circumstances. Say, for instance, we want our computer to cross the road (yes, to get to the other side) without being crushed in the traffic. We need to be able to build in a condition to our instruction, so that the computer will only cross the road if there is no traffic in sight. Instructions like these are called Conditional Statements, Conditional Constructs, or simply, Conditionals.

The first, and probably most frequently used, of these is the IF-ENDIF statement. Every one of the languages we deal with has one. Many languages, like our own AnyLang, use an IF-THEN-ENDIF construct; in those that don’t, the THEN part is implied. I’m going to use AnyLang throughout this explanation for simplicity sake, but once we reach the end of our exercise, I’ll show you how to do the same various other programming languages and explain the differences between them.

Using AnyLang, we would instruct our computer not to cross the road in traffic in the following manner :

go to side of road
IF traffic present THEN
do not cross the road
END IF

Simple enough. Our computer will go to the side of the road, and if there is traffic present it will not cross. Great, but it’s also going to keep on standing at the side of the road until hell freezes over. Why? Because we haven’t told it what to do if there is no traffic present, that’s why. We have to extend our conditional construct to take care of that possibility. To do this we use an IF-THEN-ELSE-ENDIF conditional

go to side of road
IF traffic present THEN
do not cross the road
ELSE
cross the road
END IF

Now, imagine our computer is standing at the side of a road next to a pedestrian crossing, someone has pressed the button and the light for pedestrians is green. There is certainly traffic present, but it has stopped, waiting for the pedestrians to cross the road. Our last instruction set is not detailed enough to allow for this eventuality and our computer is going to stand patiently at the side of the road while all the other pedestrians cross, because it is following the IF traffic present part of the conditional instruction. We need to extend our conditional to include this possibility.

Conditional statements may be nested within one another, so a top-level condition may be re-evaluated and lower-level conditions applied. In our example, we have already set the condition of traffic being present. We now need the computer to look at two different possibilities under this condition.

go to side of road
IF traffic present THEN
IF green light THEN
cross the road
ELSE
do not cross the road
END IF
ELSE
cross the road
END IF

If our computer sees that traffic is present it will follow the branch for this condition and be forced to evaluate the lower-level condition of the state of the light. Now, when the light is green, even with traffic present, it will cross the road, but will refrain from doing so when the light is red. The outer ELSE of the top-level construct is not evaluated at all under these circumstances, but if there is no traffic present the computer will ignore the nested construct and proceed immediately into the top-level ELSE condition.

Unfortunately there is a problem with our code, and our computer could still end up in a tangled mess because of it. Computers, as you know, are not very fast at crossing over roads, and we don’t want to take the chance of the poor thing crossing on an amber light and being caught out halfway in the middle when it turns red! Once again we need to re-evaluate our instruction set to prepare for this possibility. We could turn the nested conditional to do with the state of the lights into a number of separate IF statements as shown below.

IF traffic present THEN
IF green light THEN
cross the road
END IF
IF amber light THEN
do not cross the road
END IF
IF red light THEN
do not cross the road
END IF
ELSE …
END IF

This is perfectly valid coding, but it is not ideal. In this scenario the computer will have to evaluate every one of the conditions separately. Even if the very first condition is the true one, it will still go on to evaluate the other two, wasting processing time that could be better used for something else. Luckily we have the ability to branch further into the conditional construct with an ELSE IF-THEN statement as follows :

IF traffic present THEN
IF green light THEN
cross the road
ELSE IF amber light THEN
do not cross the road
ELSE IF red light THEN
do not cross the road
END IF
ELSE …
END IF

In this example, if the first condition is the true one, neither of the other two will be evaluated, because, instead of being three separate conditions which each must be checked for a possible true outcome, the statements now form part of a single construct. If the last statement is true, the previous two will be still need to be evaluated before the computer makes its decision to cross the road or not, but at least in this case you negate the effect of evaluation of everything beyond the true condition as in the previous example

Right, we’ve covered every possibility our computer may face having to cross the road…or have we? To think like a programmer is to play a constant game of mental chess. You may move your queen into what you believe is a winning position on the board, but unless you work out every possible move your opponent could make, you may find yourself in an embarrassing check-mate situation. In chess, this may lead to a bruised ego, in commercial programming it could end up with someone losing all the money out of their bank account overnight, or an expensive factory production line grinding to an inexplicable halt. Logic errors, those that the programmer makes when he or she neglects to provide outcomes for every possible situation, are the hardest to trace, and usually the most expensive to correct.

How to Make a Computer Cross the Road (continued)

We left off last time with an instruction set that seemed to be enough to allow our computer to cross the road, at least on the surface. I asked, in the last instalment, for any ideas on what could be wrong with the logic we are using. I did not receive any replies, but, today I’m going to cover one of the problems, just to show you that, what we thought was pretty code, was in fact flawed.

Let’s say that our computer has turned up at the side of the road as instructed, and one of the colour filters, over the green light is broken. Because the colour filter is gone and the bulb is bare, the only light the computer can see coming from the source is white. It’s not a terrible scenario because, if no traffic is present at the time, our computer will still cross the road as we have instructed it to do, but if we were writing a commercial computer-road-crossing application we would not want to leave anything to chance. If the road was heavily used, our computer might run the risk of ending up under the wheels of an impatient driver, or at the very least causing a traffic jam – remember that computers are not very speedy at crossing roads.

Sounds like a silly scenario doesn’t it? After all, we told the computer to cross the road if there is no traffic present. Most roads will have a moment when this is true; but what if our road was the Internet, and our computer a message that can only be sent when security conditions (no traffic, and a green light) are true? Or, our computer was an instruction that had to “cross” from one state to another in an air traffic control system at a busy airport?

Okay, back to our computer for the moment. To overcome our current problem we could add another ELSE IF into our construct :

IF traffic present THEN
IF red light THEN
cross the road
ELSE IF amber light THEN
do not cross the road
ELSE IF green light THEN
do not cross the road
ELSE IF white light THEN
cross the road
END IF
ELSE …
END IF

Dangerous. We’re assuming the broken light is green. If it’s red our computer doesn’t stand a chance, and what if more than one light is broken at the same time? To overcome our broken light scenario we need to instruct our computer to determine which light is the broken one, and to act accordingly. To do this were going to nest another conditional construct, a SELECT-CASE-END SELECT construct, within the ELSE IF part that deals with white light.

ELSE IF white light THEN
SELECT light
CASE top light
cross the road
CASE middle light
do not cross the road
CASE bottom light
do not cross the road
END SELECT
END IF …

We could very well have used another nested IF-THEN-ELSEIF-ENDIF structure here, and it would have been just as effective. In some languages SELECT-CASE constructs are slightly faster, in others a little slower, and in others there is no difference at all. Unless your application is so time-critical that every millisecond counts it’s usually a matter of personal choice as to which you use. Most programmers tend to mix and match, with the trend being to favour the CASE statements when more than three or four conditions apply.

What you may not have realised as we’ve been going along is that we’ve fallen into a programmer’s trap. If you’ve already become aware of it then your synapses may already be readjusting themselves to a new mode of thinking as we speak; if not, don’t worry, the very best programmers in the world are prone to the same mistake from time to time. What is it we’ve done wrong? Everything looks fine, our computer is ready to cross the road, we’ve distinguished between the three states of the light, we’ve taken care of the possibility that one, or all three could have broken covers…
Are you thinking now about the possibility of any of the bulbs being blown? If you are, that’s great, and I’m going to leave you to build the condition into your code that will deal with that, as an exercise, but that’s not the trap. We’ve believe we’ve seen the light, and once we’ve worked out all the possible malfunctions with the traffic light we’re going to deliver a cracker of a computer-road-crossing application second to none. Are we? Take a step back.

What we’ve really done is gone down a logical path that allows us to work out every possible scenario for a computer crossing the road at a traffic light. Near the beginning of this exercise I suggested the traffic light scenario and you’ve been following me through it ever since, focussed on that one thing. There was no such distinction to start with, but once we began to delve deeper into the intricacies of traffic light management, we lost the overall picture. It’s a common mistake – we all make it – which can cost us endless hours of rewriting code and heartache.
You might be thinking now that we’ve built in the possibility of a road crossing that does not involve a traffic light scenario already. We’ve told our computer not to cross the road if there is traffic present, with or without lights. Right? Yes, we have, and in most road-crossing scenarios this would be adequate. But, as good programmers we are not paid to write adequate code; we are paid to write excellent code. We owe it to our clients, who often haven’t the foggiest idea about what we’re talking about, but trust us to do the right thing by them.

Till next time ;)

caz[at]daybreaksolutions.com