The Contract Pattern. Design by contract

Similar documents
Object Oriented Program Correctness with OOSimL

AP COMPUTER SCIENCE JAVA CONCEPTS IV: RESERVED WORDS

Assertions, pre/postconditions

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

Designing Robust Classes

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

Program Correctness and Efficiency. Chapter 2

Assertions & Design-by-Contract using JML Erik Poll University of Nijmegen

Eiffel: Analysis, Design and Programming. ETH Zurich, September-December Exception handling

Assertions and Exceptions Lecture 11 Fall 2005

Programming II (CS300)

Design by Contract: An Overview

JAVA BASICS II. Example: FIFO

Method Description for Semla A Software Design Method with a Focus on Semantics

Adding Contracts to C#

Programming II (CS300)

Assertions. Assertions - Example

Fortgeschrittene objektorientierte Programmierung (Advanced Object-Oriented Programming)

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

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

JML tool-supported specification for Java Erik Poll Radboud University Nijmegen

Lecture 10 Design by Contract

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

Extensibility Patterns: Extension Access

CSC Advanced Object Oriented Programming, Spring Specification

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

Exceptions and assertions

Pages and 68 in [JN] conventions for using exceptions in Java. Chapter 8 in [EJ] guidelines for more effective use of exceptions.

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

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

Object-Oriented Design

Program Verification (6EC version only)

Self-checking software insert specifications about the intent of a system

CSE 307: Principles of Programming Languages

Late-bound Pragmatical Class Methods

Exception Handling. Sometimes when the computer tries to execute a statement something goes wrong:

Semantics. There is no single widely acceptable notation or formalism for describing semantics Operational Semantics

Comp 249 Programming Methodology Chapter 9 Exception Handling

Java Modelling Language (JML) References

Exception Handling. Run-time Errors. Methods Failure. Sometimes when the computer tries to execute a statement something goes wrong:

ASSERTIONS AND LOGGING

Object-Oriented Design

Chapter 4.!Data Abstraction: The Walls! 2011 Pearson Addison-Wesley. All rights reserved 4-1

Static program checking and verification

Data Abstraction: The Walls

Dynamic Analysis Techniques Part 2

CSE 331 Software Design & Implementation

Chapter 14. Exception Handling and Event Handling

Formal Methods for Java

Formale Entwicklung objektorientierter Software

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

MSO Lecture Design by Contract"

Unit 4: Client View of a Component Methods

ESC/Java2 Warnings David Cok, Joe Kiniry, and Erik Poll Eastman Kodak Company, University College Dublin, and Radboud University Nijmegen

Ambientes de Desenvolvimento Avançados

FAKULTÄT FÜR INFORMATIK

Exceptions. What exceptional things might our programs run in to?

Universe Type System for Eiffel. Annetta Schaad

Exercise 3 Subtyping and Behavioral Subtyping October 13, 2017

Chapter 14. Exception Handling and Event Handling ISBN

Subclassing for ADTs Implementation

EXAMINATIONS 2009 MID-TERM TEST. COMP 202 / SWEN 202 Formal Methods of Computer Science / Formal Foundations of Software Engineering WITH ANSWERS

A Class-Level Unit Testing Tool for Java

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

Assoc. Prof. Marenglen Biba. (C) 2010 Pearson Education, Inc. All rights reserved.

3. Design by Contract

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

Chapter 3 (part 3) Describing Syntax and Semantics

JASS Java with ASSertions Detlef Bartetzko, Clemens Fischer, Michael Möller, Heike Wehrheim. Presented by Florian Froese (froesef)

The Authenticator Pattern

n Specifying what each method does q Specify it in a comment before method's header n Precondition q Caller obligation n Postcondition

Conformance. Object-Oriented Programming Spring 2015

Contract Programming For C++0x

On Preserving Domain Consistency for an Evolving Application

Checked and Unchecked Exceptions in Java

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

Type Checking in COOL (II) Lecture 10

Objectives for this class meeting. 1. Conduct review of core concepts concerning contracts and pre/post conditions

Runtime Checking and Test Case Generation for Python

Homework #1, on the class web pages later today

Spark verification features

Contracts programming for C++20

Formal Specification and Verification

Representation Invariants and Abstraction Functions

An Assertion Checking Wrapper Design for Java

CSC System Development with Java. Exception Handling. Department of Statistics and Computer Science. Budditha Hettige

The Java Modeling Language (Part 2)

JML. Java Modeling Language

Chapter 9. Exception Handling. Copyright 2016 Pearson Inc. All rights reserved.

Lecture Outline. Type systems and their expressiveness. Type Checking in COOL (II) Type checking with SELF_TYPE in COOL

Automatic Black-Box Method-Level Test Case Generation Based on Constraint Logic Programming

Formal Methods for Software Development

Outline. Inheritance. Abstract Classes Interfaces. Class Extension Overriding Methods Inheritance and Constructors Polymorphism.

Java-MOP: A Monitoring Oriented Programming Environment for Java

14. Exception Handling

Singleton Pattern Creational

Pace University. Fundamental Concepts of CS121 1

Principles of Programming Languages

Modular verification of static class invariants

Implement automatic checking of superclass assertions to support design-by-contract and Liskov Substitution Principle.

Transcription:

The Contract Pattern Copyright 1997, Michel de Champlain Permission granted to copy for PLoP 97 Conference. All other rights reserved. Michel de Champlain Department of Computer Science University of Canterbury, Christchurch, New Zealand michel@cosc.canterbury.ac.nz http://www.cosc.canterbury.ac.nz/~michel 12 August 1997 Abstract Intent Also Known As Motivation This paper describes the Contract pattern, an idiom that lets you apply assertions to guarantee pre-conditions and post-conditions of methods and invariants on the state of objects. This pattern can be used to develop reliable classes by making the Design by Contract methodology introduced by Meyer in the specific context of the Eiffel language available in Java and possibly other object-oriented languages. Provide an implementation of the Design by contract methodology [Meyer88] for developing reliable classes and create robust objects in Java. This programming pattern lets you apply assertions to guarantee the pre-conditions and post-conditions of methods and invariants on the state of objects. Design by contract Sometimes it s necessary to restrict a class interface because you don t want to provide all the possible input combinations for all collaborators. One way to achieve this goal is to make minimal and consistent methods that impose pre-conditions on input parameters. Moreover, you might want to ensure the class behavior by imposing post-conditions before methods return. You might also need to make sure that the class is always in a stable state. Such an approach can result in reliable classes to create robust objects. Consider for example a bounded counter that has both a lower and upper bound. A bounded counter object is constructed by setting these bounds. The class interface provides two methods to increment the counter: inc() that increments the counter by one and add(int n) that adds the counter by n. How do we ensure that the bounded counter class is reliable, i.e., incrementing or adding the counter is legal only when its value is less that its upper bound, and that a class instance is correct and robust? One way to deal with that problem is to rely on an exception handling mechanism 1. Such a mechanism provides an elegant way to handle errors by separating error-handling code from normal code, but it neither improves the correctness of the bounded counter class nor assures the behavior of its methods. We can improve this situation by using assertions to establish a contract between a class and its clients. This contract needs to take into account the concept of a class invariant or property lower <= count <= upper, in the case of the bounded counter 1 Assuming that the language has one, such as Ada, C++, Java, etc. 1

class that must be satisfied by all instances of a class in every stable state. A solution is to provide a precise definition of what constraints (input parameters) must be satisfied by the client, and the knowledge that this behavior (functionality of each method) will be guaranteed if it agrees to those constraints. In order to support the above solution at run-time, exceptions can be thrown whenever a contract is violated, that is when either a pre-condition, post-condition or invariant is not satisfied. In this regard, the Contract pattern is a complement to exception handling. This bounded counter class illustrates how assertions may be applied to characterize the possible states of an object and to guard its runtime consistency, i.e. lower <= count <= upper. For example, a bounded counter object is constructed by setting these bounds. The method add() has: a pre-condition (require) stating that adding n to the counter is legal only when n is greater than zero and its value is less that its upper bound and, a post-condition (ensure) promising the correct functionality of the method, and before returning a verification (using ensure) that the class invariant is satisfied. RuntimeException Assertion require() ensure() PreconditionException PostconditionException require( n > 0 && count < upper ); hold(); count += n; ensure( valueof() == oldcount + n ); ensure( invariant() ); BoundedCounter add(int n) Client return lower <= count && count <= upper; invariant() This diagram illustrates how the Contract pattern offers a solution. The implementation of the bounded counter is robust, since it guards clients against possible misuse. The advantage of using assertions, apart from providing checks to legal usage, is that they explicitly state the requirements imposed on the client and on the supplier. Applicability Use the Contract pattern to establish the behavior of an object. The designer develops an interface where assertions are the basic elements of a more formal specification for an object. Such specification of its behavior may be given by defining a pre-condition and post-condition for each method and an invariant for each class: A pre-condition exception denotes a problem in the calling method: the call did not observe the required conditions, i.e. the client s side of the contract. A post-condition exception denotes a problem in the called method: the method is not functional, i.e. fulfil the supplier s side of the contract. A class invariant defines the invariant properties of the state of each instance of the class. A class invariant ensures class instance consistency. 2

Class invariants, pre-, and postconditions, all three work together to achieve the purpose of design by contract; they should not be applied separately. Structure RuntimeException Assertion require() ensure() if ( expr == false ) throw new PreconditionException() if ( expr == false ) throw new PostconditionException() PreconditionException Supplier operation() invariant() Client PostconditionException Participants This pattern uses: Supplier (BoundedCounter) creates a reliable class by using require() and ensure() operations and by defining the class invariant(). Exception defines a root of the exception hierarchy. PreconditionException implements and returns a message containing the class and method names associated with the occurring exception. PostconditionException implements and returns a message containing the class and method names associated with the occurring exception. Assertion implements the require() and ensure() operations where each of them can throw the corresponding Precondition and Postcondition exceptions if the boolean expression (expr) is false. Collaborations The following interaction diagram illustrates the collaborations between a client and a supplier: aclient asupplier apreconditionexception apostconditionexception operation() require() ensure() ensure() invariant() 3

Consequence Implementation The Contract pattern offers the following benefits: Contracts may be used to document the method interface of a class. For example, the Java language supports special doc comments that can be extracted and automatically turned into HTML documentation. Assertions and exception handling are two complementary mechanisms. Assertions declare constraints and exceptions prescribe actions. The presence of assertions contributes to a more formal specification by expressing semantic properties of classes. Design by contract is better than defensive programming which tries to make every method responsible to every kind of possible input. Contractual obligations ensure that every component is characterized by a precise definition of what constraints must be satisfied by the client to guarantee correct functioning. This is a better approach to software reliability since it requires less work to do so and less likelihood of forgetting something. The Contract pattern can be a simple extension for several object-oriented languages such as C++ [Stroustrup91], Java [Gosling+96], Smalltalk [Goldberg+83] that handle exceptions but do not support assertion mechanisms. Consider for example the assert macro in C++ that does not benefit from the flexibility of its exception mechanism. It uses the same approach as ANSI C, that is, an interrupt handler invoking the exit() function. All these languages can control execution in the case of exceptional situations, but don t have the capability of specifying assertions. One way to solve the problem would be to define an interface that combines assertions with exception handling so that pre- and post-conditions of methods and class invariants can be defined (see implementation section). This would allow the application of the design by contract methodology in the context of these languages. A class annotated with an invariant and pre- and post-conditions for its methods may be regarded as a contract, since it specifies precisely the behavior of its instances and the constraints imposed on the interactions between the object and its clients. In terms of implementation, an assertion is a simple boolean expression that we expect to be true. In practice, assertions come in pairs: a pre-condition and a post-condition. The pre-condition requires the correct specification at the method s entry; the post-condition ensures that the method s specification and object state are correct at exit. The following illustrates how assertions are localized in a method: public void amethod() { Assertion.require( booleanexpression ); // pre-condition // statements of the method... Assertion.ensure( booleanexpression ); // post-condition Assertion.ensure( invariant() ); // invariant 4

How do you observe that the required (input) conditions are not respected? By using a pre-condition to denote a problem in the client software. The pre-condition of a method specifies what restrictions the client invoking a particular method is obliged to comply with. For example, the following is a method first() with a pre-condition requiring a non-empty list before returning the reference of the first node in a circular singly-linked list: public Node first() { Assertion.require( count!= 0 ); return last.next; Note that a missing pre-condition is equivalent to require( true ). How do you make sure that the method fullfills the supplier s side of the contract? By using a post-condition to denote a problem in the called method. The post-condition of a method states what obligations the supplier object has when executing the method, provided that the client s request satisfies the method s precondition. For example, the following is a method clear() with a post-condition promising an empty circular singly-linked list before returning: public void clear() { Node n; while ( (n = getfirst())!= null ) n = null; // delete (return it to GC) Assertion.ensure( count == 0 && last == null ); Note that a missing post-condition is equivalent to ensure( true ). How do you make sure that a class is always in a stable state? By defining the invariant properties via a protected method of the state of each instance of the class and possible subclasses. public void dec() { Assertion.require( count > 0 ); count--; Assertion.ensure( invariant() ); protected boolean invariant() { return lower <= count && count <= upper; Known Uses Eiffel [Meyer92] is a pure strong-typed object-oriented language supporting the concepts of assertions and exception mechanisms. Meyer [Meyer88] has proposed the Design by Contract methodology in the context of the Eiffel language. That methodology aims at improving software reliability through correctness and robustness. With several extensions in C++ [Cline+90, Eliens95], Smalltalk [Carillo-Castellon+96] and Java [dechamplain97], the contract pattern is not anymore exclusive to Eiffel. 5

Sample Code The following code shows how to implement the Contract pattern in Java: // Assertion.java package mdec.util; class PreconditionException extends RuntimeException { PreconditionException() { super(); class PostconditionException extends RuntimeException { PostconditionException() { super(); public class Assertion { public static void require(boolean expr) { if (!expr ) throw new PreconditionException(); public static void ensure (boolean expr) { if (!expr ) throw new PostconditionException(); The Assertion package defines the PreconditionException, PostconditionException, and Assertion classes. Extending the RuntimeException allows to throw pre- or post-condition exceptions 2 without declaring them in throws clause. These two subclasses are private to the Assertion Class. We made this implementation decision to: hide the exception handling mechanism, and catch all exceptions generated by require() and ensure() This programming pattern has the advantages of: not bothering the user to handle himself his exception(s) not cluttering the method signature with throws clause offering a Eiffel s look and feel in terms of require and ensure constructs 2 In the class Assertion and all classes that use the require() and ensure() methods. 6

Classes that uses Assertion have the ability of defining more robust classes. For example, BoundedCounter class imports Assertion (line 8) and implements its own invariant method (lines 59-61): 1 // BoundedCounter.java 2 3 /** 4 * A bounded counter is a counter that has a lower and 5 * upper bound that are set when constructing the object. 6 */ 7 8 import mdec.util.assertion; 9 10 class BoundedCounter { 11 public BoundedCounter(int initialcount, 12 int lower, int upper) { 13 Assertion.require( lower < upper ); 14 count = initialcount; 15 this.lower = lower; 16 this.upper = upper; 17 Assertion.ensure( invariant() ); 18 19 20 public BoundedCounter(int lower, int upper) { 21 count = 0; 22 this.lower = lower; 23 this.upper = upper; 24 Assertion.ensure( invariant() ); 25 26 27 public void inc() { 28 Assertion.require( count < upper ); 29 count++; 30 Assertion.ensure( invariant() ); 31 32 33 public void dec() { 34 Assertion.require( count > lower ); 35 count--; 36 Assertion.ensure( invariant() ); 37 38 39 public void add(int n) { 40 Assertion.require( n > 0 && count < upper ); 41 hold(); 42 count += n; 43 Assertion.ensure( valueof() == oldcount + n ); 44 Assertion.ensure( invariant() ); 45 46 47 public int valueof() { 48 return count; 49 50 51 private int count, lower, upper; 52 53 // Method(s) and variable(s) related to the class invariant. 54 55 private void hold() { 56 oldcount = count; 57 58 59 private boolean invariant() { 60 return count >= lower && count <= upper; 61 62 63 private int oldcount; 64 7

Conclusion Meyer s work is well documented in the Eiffel context, but unfortunately not for all the other object-oriented languages interested to profit from Meyer s contribution. We have presented a programming pattern that simulates Eiffel s design by contract features in Java. This idiom can be implemented in other object-oriented languages that supports exception handling, eg, Ada, C++ and Modula-3. In addition, this idiom does not support Meyer s more recent work that addresses the problem of design by contract in a concurrent environment [Meyer93]. Acknowlegment I would like to thank Liping Zhao, Doug Lea, Wolfgang Kreutzer, Paul Ashton, and Neville Churcher for their insightful comments on this paper. References [Carillo-Castellon+ 96] M. Carillo-Castellon et al., Design by Contract in Smalltalk, JOOP, Nov-Dec 1996, pp. 23-28. [Cline+ 90] M. Cline and Lea. D, The Behavior of C++ Classes, In Proc. Symp. on Object-Oriented Programming, Marist College, 1990. [dechamplain 97] M. de Champlain, Designing by Contract in Java, Invited Talk, Department of Electrical and Computer Engineering, Concordia University, May 1997. [Eliens 95] A. Eliens, Principles of Object-Oriented Software Development, Addison-Wesley, 1995. [Goldberg+ 83] A. Golberg. and D. Robson, Smalltalk-80: The Language and its Implementation, Addison-Wesley, 1983. [Gosling+ 96] J. Gosling et al., The Java Language Specification, Addison-Wesley, 1996. [Meyer 88] B. Meyer, Object-Oriented Software Construction, Prentice-Hall, 1988. [Meyer 92] B. Meyer, Eiffel: the Language, Prentice-Hall, 1992. [Meyer93] B. Meyer. "Systematic Concurrent Object-Oriented Programming", Communication of The ACM, Vol36(9), pp56-80, 1993. [Stroustrup 91] B. Stroustrup, The C++ Programming Language, 2nd ed. Reading, MA, Addison-Wesley, 1991. 8