Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Course: Y302 - Software Engineering Course: Y302 - Software Engineering What is a program specification? Lecture 5: Specifying Java Programs It is a form of “contract” between a software customer and a software producer: Aims and Objectives Pre-conditions This lecture aims to: ! Introduce the basic ingredients of a program specification. ! Show how to map Object-Z specifications into program specifications ! Define reasoning rules for The customer provides » software requirements » acceptable conditions Post-conditions The software provides » a program which satisfies the requirements » “assignment” » “if-else” statements, ! Requirements and acceptable conditions of a software can be derived from more abstract formal specifications (e.g. ObjectZ) Illustrate the use of a defensive and a non-defensive approach in programming Lecture 5: Specifying Java programs Program Slide Number 1 Lecture 5: Specifying Java programs Slide Number 2 A program specification can be seen as a contract between the software customer and the software producer. A software customer is the person who provides the conditions (if required by the software developer) under which the software is supposed to run correctly, as well as the requirements. Such conditions are expressed in a program specification as “pre-conditions”, and they are mainly constraints on the input parameters that (components of ) a software system is supposed to receive. The requirements are instead “post-condition”, constraints on the output of the software, i.e. on the results of (the components of ) the software. With the previous lecture notes, we have concluded the first topic of this part of the course, namely object-oriented specifications of system requirements and design. The remaining set of lecture notes will be focused on a lower level of specification, that of a program specification. and on reasoning techniques used to verify the correctness of small Java programs. The main aim of this last part of this course is to introduce basic constructs of an (object-oriented) program specification, and learn simple reasoning rules for checking the correctness of basic program statements such as assignment, if-then-else, while loop statements, as well as reasoning about the correctness of method calls. The software developer has the task of developing the software and guaranteeing that the requirements are met. A program specification can therefore be seen as an agreement between these two parties, more specifically between the customer and the program (developed). The agreement statement is of the form “Provided that the program is used within the agreed conditions (e.g. on input variables), then the program performs the required task”. Writing a specification of a program and reasoning with the specification and the program code, means guaranteeing that such agreement is satisfied. We will also see how, and to which extend, an Object-Z specification can be mapped “directly” into a program specification and program skeleton. We will conclude this lecture illustrating example programs developed using the defensive and the non-defensive approaches to program design. We will assume, throughout this last part of the course, that program specifications are written in classical logic. We have already seen how to write formal specifications and system requirements, using for instance Object-Z language. These specifications can “almost automatically” be mapped into program specifications. We will see in the next few slides examples of such mapping. In doing so we will gradually introduce basic constructs of a program specification. Note: My personal thanks to Krysia Broda (examples used in this part of the course are taken from her lecture notes.) 1 2 Course: Y302 - Software Engineering Course: Y302 - Software Engineering Formalising specifications: convention Specifying Java Methods (1) Specification expressions are written: //pre: none // post: (result = x ∨ result = y) & (result<=x & result<=y) » using basic logical notations; » within “comments” lines of the (Java) programming language » using the following prefixes: » modifies: for ∆-list » pre: for pre-conditions » post: for post-conditions » loop invariant: for loop invariants » loop variant: for loop variants » invariant: for class invariants » using any parameter of the program Lecture 5: Specifying Java programs Pre-condition Post-condition int IntMin(int x, int y) { int r; if (x<=y) r = x; else r = y; return r; } • Pre-conditions are constraints only on the input variables of a method; • Post-conditions are constraints on the output of a method. They can also refer to the input variables, and to the class attributes. The variable “result” stands for the value returned by the method. • Pre-conditions are checked on entry. Post-conditions are checked on exit. Slide Number 3 Lecture 5: Specifying Java programs We will use the following convention to write our program specifications. The examples that we’ll be using are simple enough to not require very elaborated logical notations. We might, sometime, complement the logical notation with some English, if necessary. Slide Number 4 Program specifications aim to check that a program fulfils its purposes. Using just testing, we can check that given specific values to the input variables of a method, the method behaves correctly. But we can never be sure that the method will work correctly on all possible input. The book “Reasoned Programming” gives examples of program specifications with respect to the functional programming language Miranda and the imperative programming language Modula-2. In Miranda the comment line is defined by ||, whereas in Modula-2 a comment line starts with a *. We will adopt instead the notation of Java: so our specifications, if limited to just one line will start with //, and if longer than a line will be delimited by the comment symbols /*…..*/. Given a pre-condition and a post-condition to a method definition, we can instead check that for any possible value of the input variables that satisfies the pre-condition, the code of the method makes the post-condition true. This is what we mean by checking correctness of a (Java) method. The main constructs of program specifications that we are going to consider are pre-condition, postconditions, loop invariants, loop variants, and class invariants. Each of these constructs are going to be identified in our annotated (i.e. specified) program with the key words “pre:”, “post:”, “loop invariant:”, “loop variant:”, and “invariant”, respectively. The key word “modifies” is instead used to define the attributes of an object that a given method is supposed to change. In general, pre-conditions are only conditions on the input variables of a method, which must be true before a method is executed. Post-conditions are conditions on the output of the method and/or on the attributes’ values of the object, which must be true after the operation has been performed, and given that the pre-conditions are also true. Above is an example of pre- and post-conditions for a simple method, called IntMin, which returns the minimum of two integer numbers given as input variables. Note that, post-conditions can also refer to the input, but pre-conditions can refer to only the input. All but the loop invariant and loop variants are program specification’s constructs that can be derived from a given Object-Z specification. Parameters used in the program code can also be used in the program specifications 3 4 Course: Y302 - Software Engineering Course: Y302 - Software Engineering Specifying Java Methods (2) Specifying Class Invariants public class TwoNumbers{ int u, v; //invariant: u ≥ 2 ∧ v ≥ 3; public class TwoNumbers{ int u, v; // modifies u, v; //pre: none //post: u = v0 ∧ v = u0; void Swap( ) { int temp; temp = u; u = v; v = temp; } • Invariants: » are declared immediately after the attributes declarations in a class; » express constraints on the values of the attributes of a class; » behave like post-conditions of the constructor and of each methods in the class. } • Post-conditions can also express constraints on the new values of the attributes of an object. The attribute_name (i.e. u) denotes the value of the attribute after the execution of the method, attribute_name0 (i.e. u0) denotes the value of the attribute at the start of the method execution. e.g. • The modifies statement declares instead that the method is supposed to change the values of the attributes u and v. Lecture 5: Specifying Java programs Class Invariant void incrementU(int incr) { u = u + incr;} public class TwoNumbers{ int u, v; //post: u ≥ 2 ∧ v ≥ 3; void incrementU(int incr) { u = u + incr;} } Lecture 5: Specifying Java programs Slide Number 5 What is wrong here? Slide Number 6 Program specifications aim to check that a program fulfils its purposes. Using just testing, we can check that given specific values to the input variables of a method, the method behaves correctly. But we can never be sure that the method will work correctly on all possible input. This is an example of post-condition of a method that expresses constraints on the values of the attributes of the class, after the method is executed. The notational convention that we adopt here is to use in the post-condition just the name of the attribute to refer to the new value of that attribute after the execution of the method, and the name of the attribute with the subscript 0 to refer to the value of the attribute at the start of the method execution. Given a pre-condition and a post-condition to a method definition, we can instead check that for any possible value of the input variables that satisfies the pre-condition, the code of the method makes the post-condition true. This is what we mean by checking correctness of a (Java) method. Whenever a method is supposed to change the value of a class attribute, we include before the preconditions the construct “modifies” and the list of the attributes that can be changed by the method. Above is an example of pre- and post-conditions for a simple method, called IntMin, which returns the minimum of two integer numbers given as input variables. In general, pre-conditions are only conditions on the input variables of a method. Post-conditions are conditions on the output of the method, and/or on the attributes’ values of the object, after the operation has been performed. Note that, post-conditions can also refer to the input, but preconditions can only refer to the input. 5 6 Course: Y302 - Software Engineering Course: Y302 - Software Engineering Example: Mapping the CreditCard schema Mapping Object-Z into Java Specifications CreditCard General rules for the mapping: Object-Z public class CreditCard{ private final init limit = 1000; private int balance; //invariant: limit ≥ 0; //invariant: balance + limit ≥ 0 " (Init, withdraw, deposit, withdrawAvail) limit: N Java Specification limit ∈ {1000, 2000, 5000} class schema “ClassName” public class “ClassName” balance: Z Constants final attributes of the class balance + limit ≥ 0 Attributes Attributes of the class Axioms of the state schema Invariants withdraw ∆(balance) amount?:N N Initial schema Constructor of the class Operation schema » ∆-list; » pre-conditions; » axioms; Method declaration with » modifies list; » pre-conditions; » post-conditions; Visibility List “public” / “static” prefixes. Lecture 5: Specifying Java programs Init balance = 0 public CreditCard( ) { balance = 0; } //modifies: balance; //pre: amount ≤ balance0 + limit; //post: balance = balance0 – amount; public void withdraw(int amount) {……} amount?<=balance + limit balance' = balance – amount? withdrawAvail ∆(balance) amount!:N N //modifies: balance; //pre: none; //post: balance = – limit ∧ result = balance0 + limit; public int withdrawAvail( ) {……} amount! = balance + limit balance’ = – limit Slide Number 7 Lecture 5: Specifying Java programs } Slide Number 8 In this slide we give an example of how we could map part of the class schema CreditCard we saw in Lecture 3 into a Java program and its specification. Few things are interesting to notice. In this slide we give basic rules for mapping Object-Z specifications into Java program and program specifications. Refinement of formal specifications into programs and program specifications can be done in various different ways, depending on the relation between the classes specified in Object-Z and the Java classes declared in the program. The assumption that we are using here is that the Object-Z specification provides already the architecture definition of our Java program. This means that each class schema defined in Object-Z is expected to be implemented by a Java class in our Java program. This explain the first row of the mapping given in this table. First of all, the constant “limit” is defined in Object-Z to be a natural number. In Java we don’t have natural numbers as basic types, so the declaration of the final attribute limit in Java is a refinement of that given in Object-Z. It is defined as an integer with the addition of an extra invariant that has not been specified in the Object-Z class schema. Second, the constant definition in Object-Z declares limit to be of type enumeration by specifying the possible values that it could assume. In the actual implementation, the engineer will need to make a decision and define a value for the final attribute limit. Again, this is another example of simple refinement of the given formal specification. Attributes defined in a class schema (constants and variables) are mapped into attributes of our Java class, preserving the same distinction of constants and variables. So all the constants of a class schema are Java class’s attributes declared as “final”, and all the variables of a state schema are not final attributes of the Java class. Note that initialisation values given in the axiom part of a constant definition in Object-Z can be used to initialise the final attributes. This explains the second and third rows of the mapping given in this table. Third, the pre-condition of the method “withdraw” is necessary for the class invariant to be satisfied. In the Object-Z class schema definition, such pre-condition would be redundant. In the actual implementation, if this method is not declared to throw exceptions, the pre-condition is essential. We’ll see later how the choice of a defensive vs a non-defensive approach to the implementation leads to different codes and program specifications. The axioms of a state schema are mapped into invariants of our Java class. The Initial schema in Object-Z corresponds to the Java constructor of the Java class. Operation schemas are mapped into Java method specifications, in the following way. The ∆-list declared in the operation schema is mapped into a “modifies” construct, the pre-condition axioms are mapped into pre-conditions, and the remaining axioms of an operation schema are mapped into postconditions of the method. For simplicity we assume that each operation schema in Object-Z can have only one output variable. Finally, if the class schema includes a visibility list, then for each feature (attribute and operation) included in the visibility list, the corresponding Java feature will be declared to be public and the remaining features declared to be private. NOTE: For simplicity we restrict ourselves to class schemas whose attributes are of basic types (natural; numbers, real numbers, seqchar). 7 8 Course: Y302 - Software Engineering Course: Y302 - Software Engineering Reasoning about Programs: notations Mid-conditions • Program code includes variable assignments, thus variables change in their values. Mid-conditions are specifications (or expressions) that can be included at any arbitrary point within a program code. They are supposed to hold whenever the program control passes throughout the point where they are stated. • When reasoning about correctness of method codes, we have to be able to refer to current, previous and intermediate values of variables. Convention: » At each point of a method code, “variable_name” denotes the value of the Example: variable at that current point of execution of the code (i.e. now); » A “variable_name0” denotes the value of the variable at the start of a method to distinguish it from the current value; » A “variable_namei” ( “i” is a positive number) denotes an intermediate value of the variable assumed after the start of a method execution up to and excluded the current point. Example MethodA( ){ x =1; x=x+1;} Lecture 5: Specifying Java programs // pre: none int z; // y = y0 ∧ x = x0 z = x; // y = y0 ∧ z = x0 x = y; // x = y0 ∧ z = x0 y = z; // y = x0 ∧ x = y0 // post: x = y0 ∧ y = x0 // x0 = value of attribute x at the start // x = 1; x0 = value of attribute x at the start // x1 = 1; x = x1+ 1 = 2; x0 = value of x at the start Slide Number 9 Lecture 5: Specifying Java programs Pre-conditions = mid-conditions at the start Post-conditions = mid-conditions just before exit Mid-conditions = used to help justify code Slide Number 10 Mid-conditions can be used to reason about programs, for instance to show that the post-conditions of a methods are met given the code and that the pre-conditions are true. We can reason with mid-conditions in two different ways: “forward” starting from the initial mid-condition (i.e. the pre-condition) and following the statements to derive a new mid-condition and so on, until we reach the end of the code. The last mid-condition so generated is supposed to be equal to post-condition for the post-condition to be satisfied. Another way for generating mid-conditions is reasoning “backwards” from the last-midcondition (i.e. post-condition). Starting from the end, we can look at the operation in the code and substitute in the last mid-condition the variables accordingly to simulate backwards what the code is supposed to do. We discuss here how we can generate the mid-conditions given in the example here by reasoning forward and by reasoning backwards. An important feature of imperative or OO programming languages is the operation of assignment. Variables can change their values within the body of a method. To reason about the correctness of a method, namely to check whether a post-condition is satisfied at the end of a method, it’s important to keep truck of the different values that a variable can assume during the execution of the method. To keep truck of these different values of each variable, we use the following conventions. Variables at the beginning of a method are denoted by their name with the subscript 0, variables at a currents point of execution of a method, are denoted with just their name. When we perform reasoning about a part of a code, each intermediate value assumed by the variable within this code is denoted with the variable name subscribed with an (incremental) indexing number. This convention relates to the convention for writing post-conditions that we have defined in slide 5. If the current point of execution is at the end of the method code, the current value of a variable is the value at the exit of the method. Hence, the post-condition uses just the variable name to indicate the variable’s value at the current point that is at the exit of the method. Reasoning forward: At the start of this piece of code, the variables x and y are equal to some initial values x0 and y0 respectively. This is our first mid-condition (or pre-condition of our piece of code). To second mid-condition is generated looking at the code. At the point after the assignment z = x; the variable z includes the value of x just before the assignment. i.e. z = x0. The variable y is instead left unchanged. This gives our second mid-condition. We can used a similar reasoning to show how we get the third mid-condition and then the four mid-condition. Since there is no more code, we want this last mid-condition to be equal to the post-condition. This is the case, so we can say that our piece of code satisfies the given post-condition. We have given here an example of the use of this notation, by commenting each line of the code of MethodA. These comments are called “mid-condition”, and define the current value of variables at a certain point of execution, possibly referring to previous or initial values of the variables. We define in the next slide what a mid-condition is and why it’s useful. Backward reasoning: We start from the post-condition. This is also our last mid-condition. We then look at the last operation and we generate the previous mid-condition by substituting in the last midcondition the variable y with z. And so on, until we reach the first mid-condition. This is what we initially had as pre-condition, so the piece of code satisfies the post-condition. The backward reasoning helps us identify those pieces of information about the initial conditions that are necessary for the code to establish the post-condition. Such (minimal) set of information about the initial conditions are called “weakest pre-conditions”. 9 10 Course: Y302 - Software Engineering Course: Y302 - Software Engineering Reasoning rules for assignments Examples program mid-cond-before {x = expr} mid-cond-after ……… x = x-3; ……… Meaning: If the mid-cond-before holds and the assignment x=expr is executed then the mid-cond-after holds. mid-condition before // x > 10; // x > 5; x > 8 {x=x-3;} x > 5, which is true; iii.x > 10 implies x > 8? This is obviously true mid-condition after To show it: program Replace in mid-cond-after all occurrences of x with expr, This gives a new mid-condition, called mid-cond-before', so that mid-cond-before' {x = expr} mid-cond-after is true. iii. Show that mid-cond-before implies mid-cond-before' ……… x = x-1; ……… // 0 < x < N+1 // 0 ≤ x < N; mid-condition after Slide Number 11 Lecture 5: Specifying Java programs In this slide, we give the general rules for reasoning about assignments. The statement “mid-condbefore{x=expr}mid-cond-after” is called a judgment. This reasoning can be used in two ways: if both mid-conditions are given, it just shows that assuming the mid-cond-before to be correct, the assignment operation satisfies the mid-cond-after. If only the mid-cond-after is given together with the assignment, then it helps identify the minimal mid-cond-before that is needed in order to verify the correctness of the operation. Note that it is easier in general to work from mid-cond-after to mid-condbefore. (The weakest pre-condition is x > 8) mid-condition before i. ii. Lecture 5: Specifying Java programs i. Substitute x-3 for x in the mid-cond-after; ii. mid-cond-before' = x-3>5; or x > 8; so we have i. Substitute x-1 for x in the mid-cond-after: ii. mid-cond-before' = 0 ≤ x-1 < N, which gives 1 ≤ x < N+1, which is true; iii.0 < x < N+1 implies 1 ≤ x < N+1. (The weakest pre-condition is 1 ≤ x < N+1) Slide Number 12 This slide shows two examples of reasoning with mid-condition before and mid-condition after in the case of just assignment operations. Both examples have the two mid-conditions specified. The reasoning on the right-hand-side show that given that the mid-condition before is satisfied then the mid-condition after is also satisfied after the operation of assignment is performed. In both cases, the backward reasoning generates a weakest pre-condition which may or may not be equal to the given first mid-condition. To show that the code is correct, we need to show that the initial mid-condition does entails the weakest pre-condition. Reasoning about sequences of statements is based on reasoning about the individual statements in the way illustrated above. For instance, suppose that we want to reason about the following judgement: mid-cond-before{statement1; statement2}mid-cond-after This can be split into the following two judgements: mid-cond-before{statement1}mid-con-between mid-cond-between{statement2}mid-cond-after Both the above judgements are satisfied if and only if the first judgement is satisfied. This is essentially the mechanism we are going to use to prove that the post-condition of a method is satisfied whenever the pre-conditions are satisfied. The body of the method is essentially a sequence of statements, the pre-condition is the first mid-condition before and the post-condition is the last midcondition after with respect to the body of the method. The reasoning should then check the satisfiability of all the intermediate mid-conditions for all the statements included in the body of the method. 11 12 Course: Y302 - Software Engineering Course: Y302 - Software Engineering Conditionals Reasoning rules for conditionals //pre: none; //post: (result = x0 ∨ result = y0) ∧ (result ≤ x0 ∧ result ≤ y0) int intmin(int x, int y) { // x = x0 ∧ y = y0 if (x <= y) // x0 <= y0; return x; // result = x0 & result <= y0; else // x0 > y0; return y; // result = y0 & result < x0; } mid-cond-before {IF test {s1}ELSE {s2}} mid-cond-after Meaning: If the mid-cond-before holds and the test is true and {s1} is executed then the mid-cond-after holds, and if mid-cond-before holds and the test is false and {s2} is executed then the mid-cond-after also holds. To show it: i. Show mid-cond-before & test {s1} mid-cond-after ii.And show mid-cond-before & ¬test {s2} mid-cond-after There are two branches of execution, the THEN (when the condition is true) and the ELSE branch, when the condition is false. We need to show that the post-condition holds independently from the branch that is executed. Lecture 5: Specifying Java programs Slide Number 13 Lecture 5: Specifying Java programs We want to show that after each return the post-condition is true. The if-else statement always requires a case analysis. Take the first branch (or first case). To get on this branch the program must have passed the if-test. So assuming x0 to be the initial value of x, and y0 to be the initial value of y, we know that at this point of the execution, x0 <= y0. We can then annotate it as mid-condition of the program at this particular point of the execution. The program then return x. Therefore result = x0 is true and so it’s the expression result = x0 ∨ result = y0. Since x0 <= y0, we also know that result <= y0 (this is the next mid-condition). Moreover we also have result <= x0, and thus the second part of the mid-condition is true. So also the second part of the post-condition is true. The other branch (or second case) is similar. On entering it we know that x0 > y0. Since the method returns y, we have that result=y0 is true and so it’s the expression result = x0 ∨ result = y0. Moreover, we also have result < x0 and thus the second part of the mid-condition is true. This shows at each return point that the postcondition is true. Slide Number 14 In this slide, we give the general rules for reasoning about if-else statements, or conditionals. A conditional judgement is equivalent to two judgements of the form: mid-cond-before & test {S1} mid-cond-after, mid-cond-before & ¬test {S2} mid-cond-after. Check that the conditional judgement is satisfied means therefore to check that both the above two judgements are satisfied. This means showing that whatever execution branch is taken by the program under the mid-cond-before, it is always possible to establish the truth of the mid-condafter. To verify each of the above two judgments independently, we make use of the same (backward) reasoning shown for the assignment statement. Starting from the mid-cond-after, making appropriate substitutions and getting a new mid-cond-before', which should be implied by the given mid-cond-before together with the truth or falsity of the if-condition, according to which of the two judgments we are analysing. A similar reasoning can be done backwards starting from the post-condition. We want to show (result=x0 ∨ result=y0) and (result <=x0 ∧ result<=y0). On the if branch, we have as last operation return x. So we can substitute result for x and get (x=x0 ∨ x=y0) and (x ≤x0 ∧ x≤y0). The first part (x=x0 ∨ x=y0) is true and the second part is true because the mid-condition before the test would in this case be x=x0 ∧ y=y0, we have that x<=y0 is true. Analogously for the other branch. NOTE: in the second type of reasoning the new mid-conditions-before' generated from the postcondition are equivalent to the mid-conditions given in the program. In the next slide we give the general rules for reasoning about if-else statements. 13 14 Course: Y302 - Software Engineering Course: Y302 - Software Engineering Example Non-defensive vs Defensive Approach to Programming //pre: none; //post: (result = x0 ∨ result = y0) and (result ≤ x0 ∧ result ≤ y0) // x = x0 ∧ y = y0; int intmin( ) { // x0 <= y0; IF (x ≤ y) return x; // result = x0 ∧ result ≤ y0; // x0 > y0; ELSE // result = y0 ∧ result < x0; return y; } Non-defensive approach: Pre-conditions are used to specify the “good” values for the input parameters of a method, for which the method should behave correctly. Reasoning: Defensive approach: i. Substituting “result” with “x” in the post-condition we get the mid-cond-before': (x = x0 ∨ x = y0) ∧ (x ≤ x0 ∧ x ≤ y0), which is true, given the (test) and the initial mid-condition x = x0 and y = y0. ii.Substituting “result” with “y” in the post-condition we get the mid-condbefore': (y = x0 ∨ y = y0) ∧ (y ≤ x0 ∧ y ≤ y0), which is also true, given (¬test) and the initial mid-condition x = x0 and y = y0. Lecture 5: Specifying Java programs The program does not have any pre-condition on the values of its input parameters, but its code has to define all the appropriate output for all possible input values. Slide Number 15 Lecture 5: Specifying Java programs Slide Number 16 The choice of a defensive or non-defensive approach to the design of a system affects its implementation. In the Object-Z specifications we have introduced the concept of pre-condition, as an axiom to include in an operation schema in order to guarantee correct execution of the operation. This is what we call non-defensive approach. We haven’t seen, on the other hand, the concept of defensive approach for the definition of operation schema in a given class schema. This is because in objectoriented specifications, when an error occurs, there is no sense to talk about the new state of a given object, since the error would make the operation inapplicable. From the point of view of the implementation, when we refine an Object-Z operation schema included in a class schema into a method we could still take into consideration whether we are implementing that method using a defensive or a non-defensive approach. In the first case we would need to add to the method the necessary pre-conditions that make the operation work correctly. In the second case, we should declare that the method could throw some exceptions, and its code would have to check for these exceptions. This is another example of how the implementation of a given formal specification can be further refined at the implementation level. An example is given in the next slide. 15 16 Course: Y302 - Software Engineering Course: Y302 - Software Engineering Summary Non-defensive vs Defensive: example • Object-Z specifications can be mapped (or refined) into Java programs and program specifications. //pre: x ≥ 0; //post: result^2 = x; int sqrt(int x) { return sqroot(x); (suppose this is a mathematical function for calculating the square root of an integer). } • In a post-condition, “result” means the value returned by the method. • Variables change their values: so specification expressions carry always a notion of “now”. A undecorated variable always denotes its value “now”. • For pre- and post-conditions, “now” is, respectively, entry to and return from a method; for a mid-condition, “now” is just after the related statement has been executed. //pre: none //post: (x<0 ∧ throw exception) or (x ≥ 0 & result = sqrt(x)). int sqrt(int x) throw exception{ if (x<0) throw exception else return sqroot(x); (suppose this is a mathematical function for calculating the square root of an integer). } Lecture 5: Specifying Java programs • A subscript “0” on a variable denotes its value originally, i.e. on entry to the method it refers to. Other subscripts like “1” on variables indicate their values at some intermediate points. • Variables not mentioned in the specifications are assumed not to change. • In an IF statement, the test gives pre-conditions for the IF and the ELSE parts. Slide Number 17 Lecture 5: Specifying Java programs 17 Slide Number 18 18