Unit 9 - From model to implementation Flashcards
(a) What is an assertion?
(b) What is an assertion handling mechanism?
(c) What does it mean to have an assertion mechanism in Java?
(a) In general terms, an assertion is a claim that something is either true or false. In DbC, preconditions, postconditions and invariants are assertions. In Java, assertions are statements that evaluate to true or false. During execution an assertion that evaluates to true will have no effect; an assertion that evaluates to false indicates an error in the system.
(b) An assertion handling mechanism (or assertion mechanism for short) is a programming construct, which, at run-time, allows an assertion to be executed. The main use of an assertion mechanism is when an assertion evaluates to false, in which case the assertion handling mechanism will, in some way, alert the user of the system to that fact.
(c) To have an assertion mechanism in Java means being able to develop software in Java where the DbC conditions are checked at run-time.
Suppose that we had included the following constructor in BankAccount.
public BankAccount(int anAmount, int anOverdraftLimit) { // to create a bank account given an initial balance, // and an overdraft limit assert anAmount >= 0 && anOverdraftLimit >= 0;
// code for the constructor goes here assert getBalance() == anAmount && getOverdraftLimit() == anOverdraftLimit; }
Explain the meaning of the pre-and postcondition.
The precondition constrains the values of the arguments of the constructor to be correct: the precondition restricts the inputs to valid initial balances and valid overdraft limits. The postcondition characterises what the initial state should be in terms of the values of the arguments. In setting the initial state, the constructor must return an object in a valid state; the object must satisfy the invariant of the class.
Why are some assertions not expressible in a programming language, and what should be done in this case?
The main reason is that the language in which assertions are written is not sufficiently expressive to enable the actual condition to be written. Also, some conditions depend on information the program does not have. In these cases, the assertion should be recorded as a comment, using natural language.
What is one reason that ‘getter’ and ‘setter’ methods are useful in concurrent programs when using assertions to enforce contracts in Java?
The ‘getter’ and ‘setter’ methods provide good points to enforce synchronisation of access to data fields. Java supports locking of access to methods but not to attributes, so if there is a risk that a data field might be inconsistent for a time, synchronized ‘getter’ and ‘setter’ methods should be used.
(a) What are the essential steps in implementing a class specified in terms of assertions?
(b) What are the essential steps in implementing the client code using a method specified in terms of assertions?
(a) First, the state should be modelled. Second, the header should be defined for each method. Third, for each method, code should be included to ensure the postcondition and invariant are satisfied (remember that the precondition is a constraint on the client object).
(b) For the client, the precondition should be used as a test to ensure that any input to the service required is correct. This can be conveniently done using an if-then-else statement. The then branch could hold the message to call the service, with the else branch dealing with incorrect input.
public void deposit(int anAmount) { // a method that credits the balance with 'anAmount' assert anAmount > 0; // precondition setBalance(getBalance() + anAmount); // postcondition: check that the // new balance == old balance + anAmount }
Implement the postcondition of the deposit method in Figure 5.
The following method uses the ‘inner class idiom’, shown previously, to implement the postcondition.
public void deposit(final int anAmount) { // a method that credits the balance with 'anAmount' // define the assertion checking class class AssertionChecker { private int startBalance; AssertionChecker() {startBalance = getBalance(); } boolean precondition() { return anAmount > 0; } boolean postcondition() { return getBalance() == startBalance + anAmount; } } // check the precondition AssertionChecker assertCheck = null; assert (assertCheck = new AssertionChecker()) != null && assertCheck.precondition();
// the body of the method setBalance(getBalance() + anAmount);
// check the postcondition assert assertCheck.postcondition(); }
The BankAccount class is to be extended to include a transfer method of the following form:
public void transfer(int anAmount, BankAccount anAccount) {
// transfers ‘anAmount’ from the current
// account to ‘anAccount’
}
(a) Give suitable pre-and postconditions for this transfer method.
(b) Implement the transfer method.
a) Using the inertial convention, the method will have the following pre- and postconditions:
Preconditions (all must be true)
1 anAccount != null
2 anAmount > 0
3 anAmount
(a) What is the important characteristic of the subtyping relationship?
(b) Explain how inheritance without redefinition of inherited methods supports specialisation.
(c) Explain the meaning of each line of code in Figure 13 given that addInterest is not redefined in SpecialSavingsAccount.
(a) The subtyping relationship allows the subclass to be substituted for the class.
(b) Inheritance without redefinition does not prevent the addition of methods to the subclass. Specialisation can therefore be established through any added methods.
(c) The code is reproduced here for convenience:
1 SavingsAccount sA = null;
2 SpecialSavingsAccount ssA=new SpecialSavingsAccount(…);
3 sA=ssA;
4 sA.addInterest();
Line 1 assigns null to sA, which is a reference to a SavingsAccount object.
Line 2 creates a new SpecialSavingsAccount object and assigns it to ssA.
Line 3 assigns the SpecialSavingsAccount object referenced by ssA to the variable sA of type SavingsAccount, which is allowed under substitutability. Line 4 sends the addInterest message to the SpecialSavingsAccount object referenced by sA.
Through dynamic binding, this will cause the addInterest method of ssA to be invoked.
(a) Suppose that op1 overrides op2. What are the implications in terms of input and output if:
op1 has a weaker precondition than op2;
op1 has a stronger postcondition than op2.
(b) What does it mean if op1 has both a weaker precondition and a stronger postconditionthan op2?
(a) If method op1 has a weaker precondition than op2,then op1 will accept all input that is accepted by op2.
If method op1 has a stronger postcondition than op2, then the output of op1 will also satisfy the postcondition for op2.
(b) It means that op1 fulfils the same contract as op2.
Given the specification of addInterest in Figure 12, explain, using the call to addInterest on line // 1 of Figure 13 as an example, what problems would be caused if the specification of addInterest in SpecialSavingsAccount were redefined as follows:
public void addInterest() { // adds interest to balance // precondition: getBalance() > 1000; // postcondition: // getBalance() = (previous balance) + (calculated interest) // rest of state stays the same }
The precondition for addInterest in the SavingsAccount was true, and so did not require the client to check that its precondition was satisfied before sending the addInterest message in line // 1 of Figure 13. If however, the precondition of addInterest in SpecialSavingsAccount were changed as indicated (this is a strengthening of the precondition) it means that the call on line // 1 might well fail because the client has not been designed to meet the contract implied by the new precondition. For example, if the client invoked addInterest on an account having a balance of less than a 1000, the call would fail. This illustrates why preconditions should only be left the same or weakened in redefined methods.
Software components, or simply components, are units of software structured according to some specific object-oriented principles. These are:
- a component encapsulates data and functions;
- a component comes with a specification that clearly separates the component’s interface from its implementation;
- a component is known to client components only through its specified interface.
Name another concept that uses principles similar to those given above.
From the above principles, a component resembles the concept of an object very closely. Indeed, at a programming level, a component may well be implemented as a class instance, although it is more likely to be represented as a set of related class instances and perceived as a well defined subsystem within an application.
To complete the specification of an interface, it is necessary to specify the operations within each interface. These operations will have pre-and postconditions. Suggest a technique to specify these conditions.
As with other types of operations you have encountered on the course, an interface operation could be specified by a contract written in OCL. This would specify the operation’s context, its signature, and the pre-and postconditions. Alternatively, you could express the contract in natural language.