{[ promptMessage ]}

Bookmark it

{[ promptMessage ]}

Reasoned+Programming_Part2

Reasoned+Programming_Part2 - 6 Introduction lies closer to...

This preview shows page 1. Sign up to view the full content.

This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: 6 Introduction lies closer to the original vague intentions, not the code. So the rst step should always be to think carefully about your intentions and try to re ne them to a more precise speci cation. After that, the next step is to convert globality (speci cation) into locality (code), and this is much easier after the initial thought. In fact, there are speci c mathematical techniques, which we shall discuss later, that make much of this process automatic. At the same time, they tie the speci cation and code carefully together so you know as part of the coding process that the link between them is made. Figure 1.2 illustrates the progression from vague intention to precise code via precise speci cation. vague requirements precise execution global properties individual steps expressed in English how the algorithm does it and gestures code expressed in a programming language thinking typing precise requirements global properties what the algorithm does comments or speci cation expressed in logic Figure 1.2 1.7 Modules This distinction that we have made between speci cation and code, corresponding to users and computer, also makes sense inside a program. It is common to nd that part of the program, with a well-de ned task, can be made fairly self-contained and it is then called | in various contexts | a subprogram, or subroutine, or procedure or function, or, for larger, more structured pieces of program, a module. The idea is that the overall program is a composite thing, made up using components: so it takes on the role of user. A module can be speci ed, and this describes how its environment, the rest of the program, can call on it and what that achieves. The speci cation Programming in the large 7 describes all that the rest of the program needs to know about the module. The implementation of the module, the code that it contains, its inner workings, is hidden and can be ignored by the rest of the program. Modularization is crucial when you want to write a large program because it divides the overall coding problem into independent subproblems. Once you have speci ed a module, you can code up the inside while forgetting the outside, and vice versa. The speci cations of the modules also act as bulkheads, like the partitions in the hold of a ship that stop water from a hole spreading everywhere and sinking the ship. The speci cations compartmentalize the program so that if an error is discovered in one module you can easily check whether or not correcting it has any consequences for the others. This helps to avoid the `Hydra' problem, in which correcting one error introduces ten new ones. 1.8 Programming in the large This book makes a signi cant simplifying assumption, namely that speci cations can be got right rst time. This is usually (though not always) realistic for small programs, and so the techniques that we shall present are called those of programming in the small. The underlying idea, of understanding the users' point of view through a speci cation, is still important in large-scale programs, but the techniques cannot be applied in such a pure form (specify rst, then code). To understand why, you must understand what could possibly be wrong with a speci cation. The ultimate test | in fact the de nition | of quality of software is that it is t for its purpose. To be sure, the speci cation is supposed to capture formally this idea of tness, and if that has been done well then a correct program, one for which the code satis es the speci cation, will indeed be a quality one. But, conversely, speci cations can have mistakes in them, and this will manifest itself in unexpected and unwanted features in a formally correct program. Hence correctness is only an approximation to quality. Now there are many advantages to forgetting quality and working for correctness. For instance, we have precise objectives (write the code to satisfy the speci cation) that are susceptible to mathematical analysis, and we can modularize the program and work for correctness of small, easy parts, forgetting the wider issues. The widget manufacturer who takes an order for 2000 blue, size 15 widgets will nd life easier if he does not ask himself whether they are really the right colour, let alone whether or not their end use is to help train dolphins to run suicide missions smuggling cocaine. However, the true proof of the program is, despite all we have said, its behaviour in real life, and ultimately no programmer should forget that. The speci cation and reasoning are merely a means to an end. Never forget the 8 Introduction possibility that the speci cation is faulty. This will be obvious if correct code plainly gives undesirable behaviour, but earlier warning signs are when the coding is unexpectedly complicated or perhaps even impossible. If the speci cation is faulty, then it can be revised, which will involve checking existing code against the revised speci cations. Alternatively, the speci cation can be left as it is for the time being, with the intention of revising it for future versions or in the light of future experience. This is often quite reasonable, and provides some stability to the project, but it should be chosen after consideration and not out of inertia. The universal experience is that the later corrections are left, the more expensive it is to make them (A Stitch in Time Saves Nine), and large software projects have been destroyed by the accumulation of uncorrected errors. For programming in the large, many of the practical techniques that people use can be seen as being there to help to correct speci cational faults as early as possible, while they are still cheap to x. For instance, requirements elicitation is about how to communicate as e ectively as possible with the users, to nd out what they really do need and want then a number of design methodologies help to obtain a good speci cation before coding starts and prototyping produces some quick, cheap code in order to nd those faults (such as di culty of use in practice) that are best exposed by a working version. All of these are important issues but they are ignored in the rest of this book. 1.9 Logical notation English is not always precise and unambiguous | that is why computer programming languages were invented. In general, the fewer things that a language needs to talk about, the more precise it can be. In our speci cations, we are going to make use of logic to make precise one particular aspect of what we want to say, namely how di erent properties connect together. In English there are connecting words such as `and', `or', `but', `not', `all', `some', and so on, and in logic these are systematized and given individual symbols. The reason for the importance of these connectives is that it is the logical connections between the given properties that allow us to deduce new ones. For instance, suppose an instruction manual tells you: `If anyone envelops the distal pinch-screw parascopically, then the pangolin will unbundle.' Suppose you also know that the anterior proctor has just enveloped the distal pinch-screw parascopically. You do not need to be an expert on pangolins to realize that it is likely to unbundle. The reason is that you have spotted Logical notation 9 the underlying logical structure of these facts, and it does not depend on the nature of pinch-screws, pangolins or proctors. This logical structure shows up best if we introduce some abbreviations: E (x) (where x stands for any person or thing) stands for `x envelops the distal pinch-screw parascopically'. A stands for `the anterior proctor'. P stands for `the pangolin unbundles'. As a special case of this notation, if we substitute A for x then: E (A) stands for `the anterior proctor envelops the distal pinch-screw parascopically'. These abbreviations are not in themselves logical notation that comes in when we connect these statements together. Logic writes | ^ for `and' 8 for `for all' (re ecting `anyone') ! for `implies' (re ecting `if : : : then : : : ') Now our known facts appear as 8x: E (x) ! P ] ^ E (A) and just from this logical structure we can deduce P . Much of logic is about making such deductions based on the logical structure of statements. The general pattern is that we start from some statements A called the premisses, and then deduce a conclusion B . The argument from A to B is valid if in any situation where A is true, it follows inevitably that B is true, too. Logic gives formal rules | that is to say, rules that depend just on the form of the statements and not on their content or meaning | for making valid deductions, and if these rules give us an argument from A to B then we write A ` B (A entails B ). For example, If I have loads of money, then I buy lots of goods. I have loads of money. ` I buy lots of goods. is a valid argument There are situations where the premisses are false (for instance, if, as it happens, I am a miser then the rst premiss is false), but that does not a ect the validity of the argument. So long as the premisses are true, the conclusion (`I buy lots of goods') will be, too. However, If I have loads of money, then I buy lots of goods. I go on a spending spree. 10 Introduction ` I have loads of money. is not a valid argument. Even if the premisses are true, the conclusion need not be since I might be making imprudent use of my credit card. In this book we shall use logic to help us with, broadly speaking, two kinds of deduction related to a given speci cation of a program: rst, deducing new facts about how the program will behave when we come to use it and, second, deducing that the program code, or implementation, really does meet the speci cation. Part II of this book is entirely devoted to logic itself. 1.10 The need for formality English, and natural language in general, is tremendously rich and can express not only straightforward assertions and commands but also aspects of emotion, time, possibility and probability, meaning of life, and so on. But there is a cost. Much of it relies on common understanding and experience, and on the context. Look at the following three examples, and see how they contain progressively more that is unspoken: 1. `She sang like her sister.' 2. `She sang like a nightingale.' 3. `He sang like a canary.' (1) is fairly literal, but (2) is not | the comparison is not of the songs themselves but of their beauty, and the compliment works only because everyone knows (even if only by repute) that nightingales sing beautifully. As for (3), in a gangster lm \He" might well be a criminal who, on arrest, told the police all about his accomplices. But it is extremely inexplicit, and would be hard to understand out of context. Di erent people lead di erent lives, so these unspoken background assumptions of experience and understanding are imprecise, and this leads to an imprecision in English. To say anything precisely and unambiguously you must drastically restrict the range of what can be said, to the point where any background assumptions can also be made explicit. Then there is a direct correspondence between the language and its meaning, and you can treat the language `formally', that is, as symbols to be manipulated (which, after all, is what a computer has to do), and be con dent that such manipulations are re ected validly in the meaning. An important example of a formal language that you must already know is algebra, the formal language of numbers. Problems can often be solved symbolically by algebraic manipulations without thinking about the numbers behind the symbols, and you still obtain correct answers. An extension of this is calculus. Again the symbolic manipulations | the various rules for Can programs be proved correct? 11 di erentiating and integrating | can be carried through without you having to remember what the derivatives and integrals really mean. In fact, this is only a particular application of the word `calculus', which is Latin for `little stone'. In ancient times, one method of calculating was by using little stones roughly like an abacus, and the idea is that you can obtain correct answers about unmanipulable things through surrogate manipulations of the little stones. We now use formal symbols instead of little stones, but the word `calculus' is still often used for such a formal language | for instance, one part of logic is often called the `predicate calculus'. The other formal languages that you will see in this book are as follows: logic This is the language of logical connections between statements. This is a very narrow aspect of the statements and so the logical notation will usually need to be combined with other notations, but once we have the logical symbols expressing the logical structure, we can describe what are logically correct arguments. Another point is that the logical symbols are more precisely de ned than English words. For instance, there is a logical connective `_' that, by and large, means `or': `A or B ' has the logical structure `A _ B '. But sometimes the English `or' carries an implicit restriction `but not both' (the so-called exclusive or), and then the logic must take care to express this, as (A _ B ) ^ :(A ^ B ). programming languages These are the languages of computer actions (roughly | this is more true for the imperative language Modula-2 than for the functional language Miranda). Once they are made formal then one can work with them by symbolic manipulation and this is exactly what computers do when they compile and interpret programs. 1.11 Can programs be proved correct? We have already distinguished between quality and correctness, and explained how `correctness', conformance to the speci cation, is only relative: if the speci cation is wrong (that is, not what the user wanted) then so, too, will be the code, however `correct' it is. But at least the speci cation and code are both formal, so there is the possibility of giving formal proofs of this relative correctness | one might say that this is the objective of formal methods in computer software. It is worth pointing out that what you will see in this book are really only `informal formal methods'. There are two main reasons for this. The rst is that to give a formal correctness proof you need a formal semantics of your programming language, a mathematical account of what the programs actually mean in relation to the speci cations. We shall not attempt to do this at all, but instead will rely on your informal understanding of what the programming constructs mean. 12 Introduction The second is that true formal reasoning has to include every last detail. This might be ne if it is a computer (via a software tool) that is checking the reasoning, but for humans such reasoning is tedious to the point of impracticability, and hides the overall shape of the argument | you cannot see the wood for the trees. Even in pure mathematics, proofs are `rigorous' | to a high standard that resolves doubts | but not formal. Our aim is to introduce you to rigorous reasoning. Now even rigorous reasoning runs the risk of containing errors, so if in this book we cannot claim unshakable mathematical correctness you might wonder what the point is. We do not seem to be working to a Reasoned Program as an error-free structure. Nevertheless, the structure of the Reasoned Program, with its speci cation and reasoning included, is much more stable than an Unreasoned Program, that is, code on its own. We have a clearer understanding of its working, and this helps us both to avoid errors in the rst place and, when errors do slip through, to understand why we made them and how to correct them. 1.12 Summary The code is directed towards the computer, giving it its instructions. The speci cation is directed towards the users, describing what they will get out of the program. It is concerned with quality ( tness for purpose). By reasoning that the code satis es the speci cation, you link them together into a reasoned program. By putting the speci cation rst, as objectives to be achieved by the code, you engage in reasoned programming. Coding is then concerned with correctness (conformance with speci cation). This separation also underlies modularization. The speci cation of a module or subroutine is its interface with the rest of the program, the coding is its (hidden) internal workings. This book is about programming in the small. It makes the simplifying assumption that speci cations can be got right rst time. In practice, speci cations can be faulty | so that correctness does not necessarily produce quality. Be on your guard against this. The earlier faults are corrected, the better and cheaper. There are numerous practices aimed at obtaining good speci cations early rather than late, for instance talking to the customer, thinking hard about the design and prototyping, but this book is not concerned with these. To match the formality of the programming language, we use formal logical notation for speci cations. It is also possible to use formal semantics to link the two, but we will not do this here. Part I Programming Chapter 2 Functions and expressions 2.1 Functions From the speci cation point of view a function is a black box which converts input to output. `Black box' means you cannot see | or are not interested in | its internal workings, the implementing code. Mathematically speaking, the input and output represent the argument to the function and the computed result (Figure 2.1). `Give me input' function `I'll give you output' Figure 2.1 In Figure 2.2 the function add1 simply produces a result which is one more than its given argument. The number 16 is called an argument or an actual parameter and the process of supplying a function with a parameter is called function application. We say that the function add1 is applied to 16. Similarly, the function capital takes arguments which are countries and returns the capital city corresponding to the given country. 15 16 Functions and expressions 16 Denmark argument type:Countries argument type:number capital add1 Copenhagen 17 result type:Cities result type:number Figure 2.2 From mathematics we are all familiar with functions which take more than one argument. For example, functions + and * require two numbers as arguments. Figure 2.3 gives some examples of applications of multi-argument functions. 3 8 3 4 4 3 3 6 8 smaller power power smallest 3 81 64 3 Figure 2.3 When we rst de ne a function we need to pay attention both to the way it works as a rule for calculation (the code) and also to its overall global, external behaviour (the speci cation). But, when a function comes to be used, only its external behaviour is signi cant and the local rule used in calculations and evaluations becomes invisible (a black box). For example, whenever double is used the same external behaviour will result whether double n is de ned as 2*n or as n+n. 2.2 Describing functions We can describe functions in a number of ways. We can specify the function value explicitly by giving one equation for each individual input element or Describing functions 17 8 double 16 Figure 2.4 we can draw a diagram | a mapping diagram showing for each input element its corresponding result (Figure 2.5). However, often there will be many, even in nitely many, individual elements to consider and such methods will clearly be inconvenient. argument add1 x = x+1 add1 0 = 1 0 argument add1 1 = 2 a few equations general . 1 1 2 2 . . 3 natural numbers . an equation for each possible argument . . positive numbers showing individual mappings Figure 2.5 An alternative method is to describe the function using a few general equations (Figure 2.5). Here we can make use of formal parameters, which are names that we give to represent any argument to which the function will be applied. For example, the formal parameter x in the de nition of add1 stands for any number. The right hand side of the rule (or equation) describes the resul...
View Full Document

{[ snackBarMessage ]}

What students are saying

• As a current student on this bumpy collegiate pathway, I stumbled upon Course Hero, where I can find study resources for nearly all my courses, get online help from tutors 24/7, and even share my old projects, papers, and lecture notes with other students.

Kiran Temple University Fox School of Business ‘17, Course Hero Intern

• I cannot even describe how much Course Hero helped me this summer. It’s truly become something I can always rely on and help me. In the end, I was not only able to survive summer classes, but I was able to thrive thanks to Course Hero.

Dana University of Pennsylvania ‘17, Course Hero Intern

• The ability to access any university’s resources through Course Hero proved invaluable in my case. I was behind on Tulane coursework and actually used UCLA’s materials to help me move forward and get everything together on time.

Jill Tulane University ‘16, Course Hero Intern