What is a computer program?




A program is typically defined as a sequence of instructions for a computer to carry out in order to do a particular job, but this is perhaps a rather simplistic definition. You can also look at it another way and say that a program is a model of some aspect of the real world which you can use to mimic the behaviour of the real world. The more accurate the model is the better the results you can expect to get. For example, a program to calculate a company’s payroll is modelling aspects of the real world such as income tax legislation. A program to forecast the weather is modelling atmospheric conditions such as temperature, pressure and humidity. And a program such as the word processor I’m using to write this book is modelling things like letters, words, lines and paragraphs. Inside the computer all these things are represented as patterns of 0s and 1s but programs manipulate them in such a way as to make these patterns behave like the things they are supposed to represent. A program is not just a sequence of instructions; instead, it models objects in the real world in such a way as to mimic the behaviour you would expect from those objects as they interact in the real world. This is the basis of the object-oriented approach to programming, where the program is regarded as a collection of interacting objects rather than just a featureless sequence of instructions.
In this book you’re going to learn how to write programs in Ada, a general purpose programming language originally commissioned by the US Department of Defense. The first standard for the Ada language was finalised in 1983 and was later revised to produce a new updated standard in 1995. The earlier version is now known as Ada 83 and the later version (the one covered in this book) as Ada 95. Ada programs use a somewhat stilted kind of formal English in order to specify the operations you want the computer to perform. You provide some declarations which specify the objects that the program is going to deal with. You also provide a sequence of statements specifying the actions you want performed on those objects and the computer will perform them in order, one after the other. A set of declarations together with a sequence of statements like this makes up a procedure which you invent a name for. For example, you might write a procedure which clears the screen and call it Clear_Screen.
Computers do not understand Ada directly; the text of your procedure (the source code) must first of all be translated (compiled) into an internal form by an Ada compiler. The compiler protects you against your own stupidity by detecting a lot of common errors such as those which arise from typing mistakes, and these must be corrected before you can go any further. Once a procedure has been compiled successfully it is added to your program library. Whenever you want to perform that sequence of statements you can just refer to the procedure by the name you’ve given it. For example, you might write another procedure which needs to clear the screen before displaying something on it. All it would have to do would be to call on the services of the existing Clear_Screen procedure. This means that you don’t have to rewrite things you’ve already written, which reduces the amount of work you have to do both in writing the programs and in testing them to make sure they work properly. You can also make use of procedures written by other people without having to know all the details of how they work.
The next step for turning your procedure from a library unit into a working program is to link it (also referred to as building or binding it). This combines it with any other library units it refers to. In addition to any library units you may have written, the Ada language specification defines a number of standard library units that all Ada systems must provide (e.g. operations like input and output) and it is quite likely that your procedure will have used one or more of these, either directly or indirectly. The linker takes your procedure, any library units it refers to, any others that they refer to and so on, and binds them all together into a single executable program which you can then run.
Of course it is quite possible (almost inevitable, as you will discover!) that the program won’t work the way you expected; the compiler isn’t omniscient, so the fact that your program compiled successfully just means that it’s a valid Ada program. It doesn’t guarantee that it’s the particular Ada program you expected it to be, and it’s up to you to test it thoroughly to make sure it behaves the way you intended it to. You might hope for a program which displays a five times table but end up with a program that displays the number 5 over and over again, in which case it’s back to the drawing board: you’ll need to track down the errors (known as bugs in the trade), correct them, recompile, relink, and try again.
Writing a program which produces the right answers from sensible input is only part of the story. You also need to make sure that it still behaves sensibly with nonsensical input. For example, the program might expect you to type in a number; what happens if you type in your name instead? If the program responds with an error message, ignores the erroneous input and carries on working, fine. If the program crashes (i.e. halts unexpectedly), this is not so good. You may never get the result that the program is supposed to produce. Even worse, the program might get stuck in an infinite loop where it just ends up doing the same thing over and over again until it is forcibly halted.