Contracts. Dr. C. Constantinides. June 5, Department of Computer Science and Software Engineering Concordia University Montreal, Canada 1/71

Similar documents
Why Design by Contract! CS 619 Introduction to OO Design and Development. Design by Contract. Fall 2012

CSC Advanced Object Oriented Programming, Spring Specification

UC Santa Barbara. CS189A - Capstone. Christopher Kruegel Department of Computer Science UC Santa Barbara

Classes, subclasses, subtyping

a correct statement? You need to know what the statement is supposed to do.

Advanced JML Erik Poll Radboud University Nijmegen

Assertions. Assertions - Example

INHERITANCE & POLYMORPHISM. INTRODUCTION IB DP Computer science Standard Level ICS3U. INTRODUCTION IB DP Computer science Standard Level ICS3U

OO Design Principles

Adding Contracts to C#

CS 215 Software Design Sample midterm solutions

Design by Contract in Eiffel

PROCESS DEVELOPMENT METHODOLOGY The development process of an API fits the most fundamental iterative code development

The Contract Pattern. Design by contract

Readability [Skrien 4.0] Programs must be written for people to read, and only incidentally for machines to execute.

Classes, interfaces, & documentation. Review of basic building blocks

Type Hierarchy. Comp-303 : Programming Techniques Lecture 9. Alexandre Denault Computer Science McGill University Winter 2004

Data Structures. BSc in Computer Science University of New York, Tirana. Assoc. Prof. Marenglen Biba 1-1

Object Oriented Programming: Based on slides from Skrien Chapter 2

3. Design by Contract

Fortgeschrittene objektorientierte Programmierung (Advanced Object-Oriented Programming)

Midterm Exam (REGULAR SECTION)

CSE 331 Midterm Exam 2/13/12

Csci 102: Sample Exam

References: internet notes; Bertrand Meyer, Object-Oriented Software Construction; 10/14/2004 1

CHAPTER 6 Design by Contract. Literature. When Design by Contract? Why Design By Contract?

Queue Implemented with a CircularArray. Queue Implemented with a CircularArray. Queue Implemented with a CircularArray. Thursday, April 25, 13

CSE 331 Final Exam 3/16/15 Sample Solution

CS 10, Fall 2015, Professor Prasad Jayanti

Interfaces & Generics

Object-Oriented Languages and Object-Oriented Design. Ghezzi&Jazayeri: OO Languages 1

Type Hierarchy. Lecture 6: OOP, autumn 2003

csci 210: Data Structures Stacks and Queues

CS3500: Object-Oriented Design Fall 2013

17. Assertions. Outline. Built-in tests. Built-in tests 3/29/11. Jelle Slowack, Bart Smets, Glenn Van Loon, Tom Verheyen

CMP Points Total Midterm Spring Version (16 Points) Multiple Choice:

[ L5P1] Object-Oriented Programming: Advanced Concepts

Computer Science 62. Bruce/Mawhorter Fall 16. Midterm Examination. October 5, Question Points Score TOTAL 52 SOLUTIONS. Your name (Please print)

COMP 213 Advanced Object-oriented Programming Lecture 8 The Queue ADT (cont.)

17. Assertions. Jelle Slowack, Bart Smets, Glenn Van Loon, Tom Verheyen

Please note that if you write the mid term in pencil, you will not be allowed to submit a remark request.

Inheritance. Transitivity

CMP-338 Solutions Midterm Spring Version 1

Today's Agenda. References. Open Closed Principle. CS 247: Software Engineering Principles. Object-Oriented Design Principles

22c:181 / 55:181 Formal Methods in Software Engineering

ITI Introduction to Computing II

Software Development. Modular Design and Algorithm Analysis

CS 215 Software Design Sample Midterm Questions

Symbolic Execution and Proof of Properties

Rules and syntax for inheritance. The boring stuff

JAVA NOTES DATA STRUCTURES AND ALGORITHMS

September 10,

Inheritance and object compatibility

Inheritance, Polymorphism, and Interfaces

Lecture 1 Contracts. 1 A Mysterious Program : Principles of Imperative Computation (Spring 2018) Frank Pfenning

Violations of the contract are exceptions, and are usually handled by special language constructs. Design by contract

CSE 331 Summer 2017 Final Exam. The exam is closed book and closed electronics. One page of notes is allowed.

CS 32. Lecture 1: oops

CMP Points Total Midterm Spring Version (16 Points) Multiple Choice:

CSE 143 SAMPLE MIDTERM

03/29/2004. A dispenser has three essential features: adding, removing, accessing. Dispensers

JAVA BASICS II. Example: FIFO

Outline. Subtype Polymorphism, Subtyping vs. Subclassing, Liskov Substitution Principle. Benefits of Subtype Polymorphism. Subtype Polymorphism

Test-Driven Development (TDD)

Introduction to Object-Oriented Programming

CMPSCI 187: Programming With Data Structures. Lecture #11: Implementing Stacks With Arrays David Mix Barrington 28 September 2012

A Short Summary of Javali

Chapter 13 Object Oriented Programming. Copyright 2006 The McGraw-Hill Companies, Inc.

Aspect-oriented programming with AspectJ. The building blocks of AspectJ: Join points, pointcuts and advices

6.170 Recitation #5: Subtypes and Inheritance

Lecture 1 Contracts : Principles of Imperative Computation (Fall 2018) Frank Pfenning

Design by Contract: An Overview

CS 216 Exam 1 Fall SOLUTION

1B1b Inheritance. Inheritance. Agenda. Subclass and Superclass. Superclass. Generalisation & Specialisation. Shapes and Squares. 1B1b Lecture Slides

The Java Modeling Language (Part 2)

Index. Index. More information. block statements 66 y 107 Boolean 107 break 55, 68 built-in types 107

Assertions, pre/postconditions

Associate Professor Dr. Raed Ibraheem Hamed

CS18000: Programming I

Advances in Programming Languages

Programming By Contract: Designing for Correctness

+ Abstract Data Types

Hoare Logic: Proving Programs Correct

UNIT 3 ARRAYS, RECURSION, AND COMPLEXITY CHAPTER 11 CLASSES CONTINUED

Object Oriented Program Correctness with OOSimL

CT 229 Object-Oriented Programming Continued

CS 112 Programming 2. Lecture 06. Inheritance & Polymorphism (1) Chapter 11 Inheritance and Polymorphism

A Correctness Proof for a Practical Byzantine-Fault-Tolerant Replication Algorithm

An Approach to Behavioral Subtyping Based on Static Analysis

Tutorial notes on. Object relational structural patterns

Use the scantron sheet to enter the answer to questions (pages 1-6)

Practice for Chapter 11

Today s lecture. CS 314 fall 01 C++ 1, page 1

DATA TYPES. CS 403: Types and Classes DATA TYPES (CONT D)

Midterm Exam 2 CS 455, Spring 2011

ECSE 321 Assignment 2

CS171 Midterm Exam. October 29, Name:

JML Class Specifications The Java Modeling Language (Part 2) A Java Class

Inheritance and Interfaces

Cosc 241 Programming and Problem Solving Lecture 9 (26/3/18) Collections and ADTs

Transcription:

Contracts Dr. C. Constantinides Department of Computer Science and Software Engineering Concordia University Montreal, Canada June 5, 2018 1/71

Contracts in human affairs In human affairs we form legally binding documents specifying an agreement between parties, where each party is expected to satisfy certain obligations and is entitled to expect certain benefits. The legality factor implies that if one of the parties does not hold up to his or her obligations, one (perhaps a third party) should be able to assign blame. 2/71

Booking a theater seat: An analogy example Assume that you wish to book a seat for a theater play and you contact the theater s booking office in order to purchase a ticket. The ticket that you purchase constitutes a legally binding document between the theater booking office ( office ) that supplies a service and you ( the client ) who are purchasing the service. 3/71

Booking a theater seat: Obligations of the client There are certain obligations that you have as a client before this service can be provided. First, you must make a full payment. You must appear at the theater on time. You must also present a valid ticket, together with any other supporting documentation. For example, if you are a minor or if you are a student and you are eligible for a reduced price, you must also supply valid identification. Furthermore, you may also be required to follow some dress code. 4/71

Booking a theater seat: Obligations of the client /cont. Note that it is not the responsibility of the office to do any of these for you. For example, if you do not show up on time or if you do not have a valid ticket and identification, you will not be allowed in. 5/71

Booking a theater seat: Obligations of the client /cont. In formal logic, your obligations can be captured by a logical expression that must hold before you may enter the auditorium, i.e. before the service is provided. We refer to this expression as a precondition. The office benefits from your obligations: First, it collects a payment and second, it does not need to worry about you being on-time. Thus, the precondition constitutes the obligation of the client but also the benefit of the supplier. 6/71

Booking a theater seat: Obligations of the supplier On the other hand, the office has certain obligations of its own: The play to be shown must be the one advertised (the one which you have purchased the ticket for), and the play must start on-time. Furthermore, the rooms (auditorium, reception, bar, etc.) of the building must be well maintained (air-conditioned, heated). You may see the obligations of the office as your benefits. 7/71

Booking a theater seat: Obligations of the supplier In formal logic, the office s obligations can be captured by a logical expression that must hold once the play has finished (i.e. by the successful termination of the service). We refer to this expression as a postcondition. Thus the postcondition constitutes the obligation of the supplier but also the benefit of the client. 8/71

Booking a theater seat: Obligations and benefits in terms of formalisms We can tabulate the above discussion illustrating how clients and suppliers relate to preconditions and postconditions of a given service. Obligations Benefits Client Precondition Postcondition Supplier Postcondition Precondition 9/71

Booking a theater seat: Obligations and benefits /cont. It is important to note that a party that acts as a supplier for a given service, may also act as a client for another service that is needed to perform its obligations as a supplier. For example, the theater would normally act as a client to a number of suppliers in the city, such as vendors, catering services, security services, etc. 10/71

Booking a theater seat: General obligations There are also certain general obligations that must always be met such that the building must meet safety standards,that you cannot vandalize the rooms or assault the staff or other clients, etc. If any of these general obligations are violated, then the agreement between you and the office is also violated. In formal logic, these general obligations are captured by a logical expression called the invariant. The invariant must always hold from the moment you purchase the service until the moment the service has been successfully completed. 11/71

Contract programming In programming we adopt the metaphor of contracts for collaborating software elements. The agreement involved is an operation to be performed by a software element such as a method. The method acts as a supplier to any client wishing to make use of its services. The method of design by contract (dbc) (or contract programming) recommends that every software element should be associated with a contract as a specification of its interaction with the rest of the world. Note that nothing prevents a software element from acting as both a supplier and a client with different elements. 12/71

Contract programming /cont. Even though contract programming is not confined to object-oriented programming (OOP), we will use OOP as our underlying programming paradigm. In OOP we can build contracts by associating each method (which forms part of the interface of the class) with a set of preconditions and a set of postconditions, and by associating an invariant with the class. 13/71

Defining assertions on methods A contract for a software element is specified by assertions: preconditions and postconditions. Precondition: Logical expression describing the state of the system before the execution of an operation. Postcondition: Logical expression describing the state of the system after the execution and successful termination of an operation. 14/71

Defining assertions on classes Since a contract specifies the relation between an element with the outside world, we should then specify assertions for all public (and protected) methods, i.e. those which form part of the interface of the class. 15/71

Defining a class invariant In OOP we can associate each class with an invariant. The class invariant specifies the valid states for every instance of the class. An instance of a class which does not uphold the invariant is not a valid instance. 16/71

Contract programming with adbc Developed by the Ansymo research group at the University of Antwerp, Belgium, adbc is a small library that adds support for contract programming to the AspectJ programming language and subsequently to Java as well as AspectJ is a superset of Java. In adbc contracts are specified as Javascript expressions within Java annotations. Methods and advice can have pre-and postconditions; classes and aspects can have invariants. 17/71

Contract programming with adbc The following keywords are provided: @requires specifies the precondition. @ensures specifies the postcondition. @invariant $this refers to the current object. $result refers to the return value of a method/advice, available in postconditions. $old(expr) refers to the old function evaluates an expression before the method/advice is executed, stores the result, such that it is available in postconditions. 18/71

A bounded stack Consider a bounded stack that holds string objects. The Stack Abstract Data Type (ADT) implements a last-in-first-out protocol. public class Stack { public ArrayList <String> collection; public int capacity; public int top = -1; Stack (int capacity) { this.capacity = capacity; this.collection = new ArrayList<String>(capacity); } public void push (String str) {...} public String pop () {...} public String top () {...} public boolean isfull () {...} public boolean isempty () {...} public int getsize () {...} public int getcapacity() {...} } 19/71

Defining a class contract In OOP we can associate each class with an invariant. The class invariant specifies the valid states for every instance of the class. An instance of a class which does not uphold the invariant is not a valid instance. In this example the class invariant should state that the size of the stack should never be negative; that the capacity of the stack can only be a positive integer, and finally that the size cannot exceed the capacity. @invariant ({ "$this.top >= -1", "$this.capacity > 0", "$this.top <= $this.capacity" }) 20/71

Defining method contracts A contract for a software element is specified by assertions: preconditions and postconditions. Since a contract specifies the relation between an element with the outside world, we should then specify assertions for all public (and protected) methods, i.e. those which form part of the interface of the class. 21/71

Defining method contracts /cont. Class Stack contains methods void push(string) that places an element onto the collection, String pop() that removes and returns the topmost element from the collection and String top() that returns but does not remove the topmost element of the collection. 22/71

Defining method contracts /cont. For the constructor Stack (int capacity), the postcondition states that the collection atrtribute is not null. @ensures ({"$this.collection!= null" }) Stack (int capacity) { this.capacity = capacity; this.collection = new ArrayList<String>(capacity); } 23/71

Defining method contracts /cont. For method void push (..), the first precondition states that the element passed to the method must be a valid string. The second precondition states that an element can only be placed on a non-full collection. @requires ({ "str!= null", "$this.isfull() == false" }) public void push (String str) { collection.add(++top, str); } 24/71

Defining method contracts /cont. The postcondition states that the element is now held in the collection, that the element was placed on the top (and thus it is retrievable according to the stack protocol), and that the current size of the collection should now be one greater than the size of the collection prior to invoking the operation. @ensures ({ "$this.collection.contains(str)", "$this.collection.get($this.top) == str", "$this.getsize() == $old($this.getsize()) + 1" }) public void push (String str) { collection.add(++top, str); } 25/71

Defining method contracts /cont. For method String pop (), the precondition states that the collection must not be empty. @requires ({ "$this.isempty() == false" }) public String pop () { String element = collection.get(top--); return element; } 26/71

Defining method contracts /cont. The postcondition states that the element retrieved is of valid type, that the element retrieved is the one previously held on top of the stack, and that the size of the collection is one less that the size of the collection prior to invoking the operation. @ensures ({ "$result!= null", "$result == $old($this.top())", "$this.getsize() == $old($this.getsize()) - 1" }) public String pop () { String element = collection.get(top--); return element; } 27/71

Defining method contracts /cont. For method String top (), the precondition states that the collection must not be empty. @requires ({ "$this.isempty() == false" }) public String top () { String result = collection.get(top); return result; } 28/71

Defining method contracts /cont. The postcondition states that the element retrieved is not null, that the element retrieved is the one previously held on the top of the stack, and that the size of the collection has not changed. @ensures ({ "$result!= null", "$result == $old($this.top())", "$this.getsize() == $old($this.getsize())" }) public String top () { String result = collection.get(top); return result; } 29/71

Defining method contracts /cont. For method int getsize (), there is no precondition. The postcondition states that the resulting value should be a non-negative integer. @requires ({ "true" }) @ensures ({ "$result >= 0" }) public int getsize () { return this.top + 1; } 30/71

Defining method contracts /cont. Finally for method int getcapacity(), there is no precondition. The postcondition states that the resulting value should be positive. @requires ({ "true" }) @ensures ({ "$result > 0" }) public int getcapacity() { return this.capacity; } 31/71

Simulating failure scenarios We will simulate a number scenarios, imposing failures on preconditions, postconditions and invariants. For each scenario, we will state a) why the program failed and b) where exactly the program failed and c) who is to blame for the failure. 32/71

Invariant failure Consider the test program below: Stack stack = new Stack(0); stack.push("all"); stack.push("your"); stack.push("base"); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); This results in invariant failure as the client attempted to instantiate a stack of zero capacity: Exception in thread "main" [...]: Invariant broken! (postcondition) Contract: $this.capacity > 0 Where: Stack Blame: (method not found) 33/71

Invariant failure and class constructor The invariant failed because upon termination of the constructor, attribute capacity is not positive. Recall that we have not placed an appropriate precondition in the class constructor. As a result, the failure came from the invariant upon termination of the constructor method. Let us now add a precondition to the constructor, stating that the capacity parameter must be a positive number. @requires ({"capacity > 0"}) Stack (int capacity) {...} Note the difference between $this.capacity in the invariant contract which denotes an attribute, and capacity in the constructor contract which denotes a parameter. 34/71

Invariant failure and class constructor /cont. If we now attempted to create an object with zero capacity Stack stack = new Stack(0); we would get the following constructor precondition failure: Exception in thread "main" [...] PreConditionException: Precondition broken! Contract: capacity > 0 Where: Stack(int) Blame: Test.main 35/71

Precondition failures ex. 1 Consider the test program below: Stack stack = new Stack(2); stack.push("all"); stack.push("your"); stack.push("base"); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); This results in precondition failure at the third call to push() as this exceeds the capacity of the stack: Exception in thread "main" [...]: Precondition broken! Contract: $this.isfull() == false Where: public void Stack.push(java.lang.String) Blame: Test.main 36/71

Precondition failures ex. 2 Consider the test program below: Stack stack = new Stack(3); stack.push("all"); stack.push("your"); stack.push("base"); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); This results in precondition failure at the last call to pop() as the stack has already become empty: Exception in thread "main" [...]: Precondition broken! Contract: $this.isempty() == false Where: public java.lang.string Stack.pop() Blame: Test.main 37/71

Postcondition failures To simulate postcondition failures we will inject errors into the implementation of the methods of the Stack class. We will subsequently expect that the tool will indicate the appropriate failure type and pick up the particular assertion that failed. 38/71

Postcondition failures: Faulty pop() Consider the (faulty) implementation of method pop() that fails to decrement variable top upon retrieval: @requires ({ "$this.isempty() == false" }) @ensures ({ "$result!= null", "$result == $old($this.top())", "$this.getsize() == $old($this.getsize()) - 1" }) public String pop () { String element = collection.get(top); return element; } 39/71

Postcondition failures: Faulty pop() /cont. Consider the test program below: Stack stack = new Stack(3); stack.push("all"); stack.push("your"); stack.push("base"); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); The program responds with Exception in thread "main" [...]: Postcondition broken! Contract: $this.getsize() == $old4-1 Where: public java.lang.string Stack.pop() Blame: Stack.public java.lang.string Stack.pop() 40/71

Postcondition failures: Faulty top() Consider the (faulty) implementation of method top() that decrements variable top upon inspection, thus changing the size of the stack, whereas in fact it should not: @requires ({ "$this.isempty() == false" }) @ensures ({ "$result!= null", "$this.getsize() == $old($this.getsize())" }) public String top () { String result = collection.get(top--); return result; } 41/71

Postcondition failures: Faulty top() /cont. Consider the test program below: Stack stack = new Stack(3); stack.push("all"); stack.push("your"); stack.push("base"); System.out.println(stack.top()); System.out.println(stack.pop()); System.out.println(stack.pop()); The program responds with Exception in thread "main" [...]: Postcondition broken! Contract: $this.getsize() == $old2 Where: public java.lang.string Stack.top() Blame: Stack.public java.lang.string Stack.top() 42/71

Two cautionary test cases: Faulty top() The test program is as follows: Stack stack = new Stack(3); stack.push("all"); stack.push("your"); stack.push("base"); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); The program responds with Exception in thread "main" [...]: Postcondition broken! Contract: $result == $old3 Where: public java.lang.string Stack.pop() Blame: Stack.public java.lang.string Stack.pop() 43/71

Two cautionary test cases: Faulty top() /cont. The error message is not straightforward. Method pop() seems to fail to meet its postcondition even though its implementation is correct. The error lies in the conflict between the correct implementation of method pop() and a faulty method that is part of its specification, namely top(). When making the call to pop(), adbc assumes that the method s specifications is correct. As a result, adbc (mistakenly) concludes that the error can only be originating from the implementation of pop(). 44/71

Two cautionary test cases: Faulty getsize() Consider the (faulty) implementation of method getsize() that does not increment the value of variable top, whereas in fact it should, thus allowing top to have a negative value: @requires ({ "true" }) @ensures ({ "$result >= 0" }) public int getsize () { return this.top; } 45/71

Two cautionary test cases: Faulty getsize() /cont. The test program is as follows: Stack stack = new Stack(3); stack.push("all"); stack.push("your"); stack.push("base"); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); The program responds with Exception in thread "main" [...]: Precondition broken! Contract: $this.isempty() == false Where: public java.lang.string Stack.pop() Blame: Test.main 46/71

Two cautionary test cases: Faulty getsize() /cont. The error message is again not straightforward. Method pop() seems to fail meeting its postcondition even though its implementation is correct. The error lies in the conflict between the correct implementation and a faulty method that is part of the specification, namely getsize(). 47/71

How do we avoid the problem? We must carefully consider the order in which we implement and test the methods in a class. For example, the contracts for both methods push() and pop() depend on method getsize(). The contract for method pop() depends on method top(). The contract for method top() depends on method getsize(). Recommendation: Follow a bottom-up approach to implementation and testing, i.e. getsize(), top(), (push(), pop()). 48/71

A bounded queue Consider a bounded queue that holds string objects. The Queue ADT implements a first-in-first-out protocol. public class Queue { public ArrayList <String> collection; public int capacity; public Queue(int capacity) { this.collection = new ArrayList<String>(); this.capacity = capacity; } public void enqueue (String str) {...} public String dequeue () {...} public boolean isfull () {...} public boolean isempty () {...} public int getsize () {...} public int getcapacity() {...} } 49/71

Defining a class contract The class invariant should state that the size of the queue should never be negative: @invariant ({ }) "$this.collection.size() >= 0", "$this.capacity > 0", "$this.collection.size() <= $this.capacity" 50/71

Defining a constructor contract For the constructor Queue(), the precondition states that the parameter must be a positive number. The postcondition states that the attribute collection is not null and the attribute capacity is a positive number. @requires ({"capacity > 0"}) @ensures ({ "$this.collection!= null", "$this.capacity > 0" }) public Queue(int capacity) { this.collection = new ArrayList<String>(); this.capacity = capacity; } 51/71

Defining method contracts For method enqueue (String str), the precondition states that the parameter str is not null and that the collection is not already full. @requires ({ "str!= null", "$this.isfull() == false" }) public void enqueue (String str) { collection.add(str); } 52/71

Defining method contracts /cont. The postcondition states that upon successful termination of the method a) the element is now held in the collection and b) the size of the collection has been increased by one. @requires ({ "str!= null", "$this.isfull() == false" }) @ensures ({ "$this.collection.contains(str)", "$this.getsize() == $old($this.getsize()) + 1" }) public void enqueue (String str) { collection.add(str); } 53/71

Defining method contracts /cont. For method dequeue (), the precondition states that the collection must not be empty. @requires ({"$this.isempty() == false"}) public String dequeue () { String element = collection.remove(0); return element; } 54/71

Defining method contracts /cont. The postcondition states that upon successful termination of the method a) the element retrieved is not null, b) the element retrieved is the one previously held at the front of the queue, and c) the size of the collection has been decreased by one. @requires ({"$this.isempty() == false"}) @ensures ({ "$result!= null", "$result == $old($this.collection.get(0))", "$this.getsize() == $old($this.getsize()) - 1" }) public String dequeue () { String element = collection.remove(0); return element; } 55/71

Defining method contracts /cont. For method int getsize (), there is no precondition. The postcondition states that the resulting value should be a non-negative integer. @requires ({"true" }) @ensures ({"$result >= 0" }) public int getsize () { return collection.size(); } 56/71

Defining method contracts /cont. For method int getcapacity(), there is no precondition. The postcondition states that the resulting value should be a positive integer. @requires({"true"}) @ensures({"$result > 0"}) public int getcapacity() { return this.capacity; } 57/71

Simulating failure scenarios: Constructor precondition failure Consider the test program below: Queue queue = new Queue(0);... This results in a constructor precondition failure as the client attempted to create a queue with zero capacity: Exception in thread [...].PreConditionException: Precondition broken! Contract: capacity > 0 Where: public Queue(int) Blame: Test.main 58/71

Simulating failure scenarios: Method precondition failure Consider the test program below: Queue queue = new Queue(2); queue.enqueue("all"); queue.enqueue("your"); queue.enqueue("base"); This results in a precondition failure of method enqueue() as the client attempted to insert an element in a full collection: Exception in thread [...].PreConditionException: Precondition broken! Contract: $this.isfull() == false Where: public void Queue.enqueue(java.lang.String) Blame: Test.main 59/71

Postcondition failure: Faulty dequeue() Consider the (faulty) implementation of method dequeue() that removes an element from position 1 (instead of from position 0): @requires ({"$this.isempty() == false"}) @ensures ({ "$result!= null", "$result == $old($this.collection.get(0))", "$this.getsize() == $old($this.getsize()) - 1" }) public String dequeue () { String element = collection.remove(1); return element; } 60/71

Postcondition failure: Faulty dequeue() /cont. Consider the test program below: Queue queue = new Queue(5); queue.enqueue("all"); queue.enqueue("your"); queue.enqueue("base"); System.out.println(queue.dequeue()); System.out.println(queue.dequeue()); System.out.println(queue.dequeue()); This results in a postconfition failure: Exception in thread "main" [...].PostConditionException: Postcondition broken! Contract: $result == $old3 Where: public java.lang.string Queue.dequeue() Blame: Queue.public java.lang.string Queue.dequeue() 61/71

Inheritance and subtyping Classes (and interfaces) define types. All instances of a given class constitute legitimate values of that type. The inheritance relationship between classes (and between classes and interfaces) creates a related set of types (subtype relationship). Type T 2 is a subtype of type T 1 if every legitimate value of T 2 is also a legitimate value of T 1. We say that T 1 is the supertype of T 2. 62/71

Inheritance and subtyping /cont. For example, the relationship between shape and triangle defines a subtype relationship as every triangle is a shape (but not vice versa) and thus the set of shapes is a superset of the set of triangles. The relationship between stack and vector does not define a subtype relationship even though it may be practical to deploy inheritance and define the former in terms of the latter. The type defined by the subclass is a subset of the type defined by its superclasses as the set of all instances of a subclass is included in the set of all instances of its superclass. 63/71

Inheritance of contractual specifications in adbc The keyword $super in a subclass refers to the corresponding assertion in the superclass. Consider the following example: @invariant ({"$super"}) public class Queue2 extends Queue { @requires ({"$super"}) @ensures ({"$super"}) public Queue2 (int capacity) { super(capacity); } } 64/71

Inheritance of contractual specifications in adbc /cont. For the following program statement Queue2 queue = new Queue2(0); we get the following Exception in thread [...]PreConditionException: Precondition broken! Contract: capacity > 0 Where: public Queue(int) Blame: Queue2.<init> 65/71

Inheritance of contractual specifications in adbc /cont. $super is optional since by default subclasses inherit the contractual specifications of their superclasses. public class Queue2 extends Queue { public Queue2 (int capacity) { super(capacity); } } 66/71

Inheritance of contractual specifications in adbc /cont. $super can be used in logical expressions in order to extend a specification. Let a requirement for Queue2 be that its instances must have a maximum capacity of 3. @invariant ({"$super && $this.capacity < 4"}) public class Queue2 extends Queue { @requires ({"$super && capacity < 4"}) @ensures ({"$super"}) public Queue2 (int capacity) { super(capacity); } } 67/71

The Liskov Substitution Principle The Liskov substitution principle (LSP) states that in a computer program, if S is a subtype of T, then objects of type T may be replaced with objects of type S. This implies that an instance of a subclass can appear wherever an instance of a superclass is expected. For example, instances of class Triangle can appear in any place where an instance of class Shape is expected. 68/71

Inheritance, LSP and contracts: Preconditions What happens when a subclass needs to introduce different specifications than the ones in the superclass? There are two important things to recall here: First, a precondition specifies the obligations of the client, and second, instances of a subclass can be provided in all places where an instance of a superclass is expected. With these two points in mind, we can argue that if a precondition in a subclass is stronger than that of the superclass, then this is not fair to the client who has already reached a contractual agreement with the superclass. This implies that a precondition in a subclass can be the same or weaker than that of the superclass. In other words, the subclass may demand less from its clients than what the superclass already demands. 69/71

Inheritance, LSP and contracts: Postconditions Recall that a postcondition specifies the obligation of the supplier. With this in mind, we can argue that if a postcondition in a subclass is weaker than that of the superclass, then this is not fair to the client who has already reached a contractual agreement with the superclass. This implies that a postcondition in a subclass can be the same or stronger than that of the superclass. In other words, the subclass may offer more to its clients than what the superclass already offers. 70/71

Inheritance, LSP and contracts In conclusion: Preconditions cannot be strengthened in a subtype. Postconditions cannot be weakened in a subtype. As a result, Queue2 violates the Liskov substitution principle. 71/71