Adding Contracts to C#

Similar documents
Assertions. Assertions - Example

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

Object Oriented Program Correctness with OOSimL

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

Building Trust in Third-party Components using Component Wrappers in the.net Frameworks

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

Design by Contract in Eiffel

Contract Wizard II: Developing a GUI

Assertions, pre/postconditions

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

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

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

JAVA BASICS II. Example: FIFO

CSC Advanced Object Oriented Programming, Spring Specification

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

Programming By Contract: Designing for Correctness

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

Inheritance. Transitivity

Another Mediocre Assertion Mechanism for C++

What can go wrong in a Java program while running?

Type Hierarchy. Lecture 6: OOP, autumn 2003

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

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

AP COMPUTER SCIENCE JAVA CONCEPTS IV: RESERVED WORDS

The Contract Pattern. Design by contract

Data Abstraction: The Walls

Static program checking and verification

Program Verification (6EC version only)

Introduction to Programming Using Java (98-388)

Software Development. Modular Design and Algorithm Analysis

Control flow in Eiffel

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

A FLEXIBLE STRATEGY FOR EMBEDDING AND CONFIGURING RUN- TIME CONTRACT CHECKS IN.NET COMPONENTS

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

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

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

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

Wrapping a complex C++ library for Eiffel. FINAL REPORT July 1 st, 2005

Absolute C++ Walter Savitch

WA1278 Introduction to Java Using Eclipse

Proceedings of the 8 th International Conference on Applied Informatics Eger, Hungary, January 27 30, Vol. 2. pp Virtuoso Virtuality

Universe Type System for Eiffel. Annetta Schaad

September 10,

3. Design by Contract

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

Dynamic Analysis Techniques Part 2

A Third Look At Java. Chapter Seventeen Modern Programming Languages, 2nd ed. 1

CS 617 Object Oriented Systems Lecture 3 Object Abstractions, Encapsulation, Abstract Data Types 3:30-5:00pm Thu, Jan 10

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

With the popularity of the Web and the

Object-oriented Programming. Object-oriented Programming

Software Architecture Bertrand Meyer. Lecture 3: Language constructs for modularity and information hiding

Semantic Analysis. CSE 307 Principles of Programming Languages Stony Brook University

C a; C b; C e; int c;

Learning Objectives. C++ For Artists 2003 Rick Miller All Rights Reserved xli

Graphical Interface and Application (I3305) Semester: 1 Academic Year: 2017/2018 Dr Antoun Yaacoub

Zhifu Pei CSCI5448 Spring 2011 Prof. Kenneth M. Anderson

Introduction to contract programming

Test-Driven Development (TDD)

Software Architecture 4. July 2005

Exception Handling Introduction. Error-Prevention Tip 13.1 OBJECTIVES

Programming II (CS300)

Design by Contract: An Overview

Exploiting Synergy Between Testing and Inferred Partial Specifications

Last name:... First name:... Department (if not D-INFK):...

CSE P 501 Compilers. Java Implementation JVMs, JITs &c Hal Perkins Winter /11/ Hal Perkins & UW CSE V-1

Java: advanced object-oriented features

Introduction to Eiffel

Testing, Debugging, and Verification

Chapter 14. Exception Handling and Event Handling ISBN

Purpose of the Simulated function

The Java Modeling Language (Part 2)

Another IS-A Relationship

Foundations of Software Engineering Design by Contract

Motivation. Correct and maintainable software Cost effective software production Implicit assumptions easily broken

CS4215 Programming Language Implementation

Java 5. Lecture 33: Java 5. Generics Finally Added. Constrained Genericity

Exceptions. Gunnar Gotshalks EX 1

Chapter 4 Defining Classes I

VIRTUAL FUNCTIONS Chapter 10

Subclassing for ADTs Implementation

(800) Toll Free (804) Fax Introduction to Java and Enterprise Java using Eclipse IDE Duration: 5 days

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

An Assertion Checking Wrapper Design for Java

Traditional Error Handling

C#: advanced object-oriented features

Object-Oriented Design

C#: advanced object-oriented features

1 Epic Test Review 2 Epic Test Review 3 Epic Test Review 4. Epic Test Review 5 Epic Test Review 6 Epic Test Review 7 Epic Test Review 8

Fortgeschrittene objektorientierte Programmierung (Advanced Object-Oriented Programming)

CS/ENGRD 2110 SPRING Lecture 7: Interfaces and Abstract Classes

Queues. CITS2200 Data Structures and Algorithms. Topic 5

Designing Robust Classes

An Introduction to Object Orientation

Weiss Chapter 1 terminology (parenthesized numbers are page numbers)

Prelim 1 SOLUTION. CS 2110, September 29, 2016, 7:30 PM Total Question Name Loop invariants. Recursion OO Short answer

Containers: Stack. The Stack ADT. The Stack ADT. The Stack ADT

Interfaces. An interface forms a contract between the object and the outside world.

Containers: Stack. Jordi Cortadella and Jordi Petit Department of Computer Science

Interfaces (1/2) An interface forms a contract between the object and the outside world.

Transcription:

Adding Contracts to C# Peter Lagace ABSTRACT Design by contract is a software engineering technique used to promote software reliability. In order to use design by contract the selected programming language must have built in support for pre conditions, post conditions and class invariants, collectively called contracts, or some mechanism must be devised to validate the contract. This paper proposes a way of supporting contracts in C# using Resolve Corp. s extensible C# add in. Keywords Design by Contract, C#, extensible C# 1. INTRODUCTION Design by contract is a software engineering technique used to promote software reliability. This idea was made popular by Bertrand Meyer and his work on the Eiffel programming language [4]. The main idea behind design by contract is that for a routine to work properly a set of conditions must hold true before the routine is called, the pre conditions, and another set of conditions must hold true after the routine has finished its task, the post conditions. The conditions are checked using assertions and an assertion failure indicates a bug in the program. A pre condition assertion failure indicates that the bug is in the program that called the routine, while a post condition assertion failure indicates that the bug is in the routine itself. Additionally, when used in an object oriented programming language, there is a set of conditions that apply to the class of objects that must hold true for the life of the object. These conditions are called class invariants or simply invariants. The invariants are checked with the pre conditions and the post conditions on all methods that can be called from another object. An invariant assertion failure indicates a problem in the class and specifically to the routine being executed when the assertion occurred. In order to use design by contract the selected programming language must have built in support for pre conditions, post conditions and class invariants, collectively called contracts. However, only a few programming languages have built in support for contract, Eiffel being one of them. For all other languages, some mechanism must be devised in order to inject the assertion checks into methods needed to validate the contract. For C++ and Java, several mechanisms have been devised to support design by contract [1, 2, 7]. These range from using special comments and the pre processor to inheriting from a special class and embedding the contract assertions in the methods. Neither of these options will work for the C# language since there is no pre processor and only single inheritance is supported. Some mechanisms for the C# language that are a good starting point, but fail to deliver on the full idea of design by contract have been tried. One is a helper class [3] to handle the contract assertions, but there is no automatic support for inheritance. Another is a post compilation Visual Studio add in [9] that uses custom attributes to specify the contract assertions. The use of custom attributes supports inheritance, but it does not work when a class implements an interface. Additionally, the use of Eiffel s old and implies keywords are not supported. Finally, there is a proposal to modify the common language infrastructure to support contracts [8], but that is not currently supported in the C# language. There has been work on creating a separate program to add contracts to existing assemblies [5]. This program uses Eiffel classes to wrap the classes from the assembly with contracts and to that extent it is effective. However, this process is done after the assembly is built and there is no support specifying the contract assertions in the code itself. It was noted in the future work section of the paper that they are exploring the use of custom attributes to specify the contract assertions in the code. 2. Specifying the Contracts In the.net family of languages, metadata is used to store information about the program. The metadata contains information about the assembly (DLL or executable) and the types (classes, structures, enumerations, etc.) contained in the assembly along with associated attributes. The attribute metadata is used to add additional information to types or the type members. This additional information can then be used to modify the behavior of the program at runtime or, in the case of adding contracts to C#, insert assertion checks into methods and properties. 2.1 Design by Contract Attributes Each of the assertion types are specified using the same format. The first parameter is a string which is used as the label for the assertion. In the case where the assertion is not met, the label is used as the message to the user indicating what has happened. The second parameter is a string containing the assertion condition. Pre conditions use the DBCRequire attribute, post conditions use the DBCEnsure attribute and invariants use the DBCInvariant attribute. The pre condition and post condition attributes are placed directly before the method or property to which they apply and the invariant attribute is placed directly before the class, structure or interface to which it applies. Figure 1 shows an example of a simple stack interface. The last attribute used is the DBCEnable attribute. This attribute is used to specify which types of assertions are used and how the assertions are implemented. The enable attribute can be used at the assembly level, class level or method level. There are several ways of specifying the enable attribute. The easiest way is to use the enable attribute is to pass a Boolean which indicates whether the assembly is being built for release or for testing. When the value is false, all assertion types are enabled and are implemented using an Assert statement. When the value is true, only the pre condition assertions are enabled and they are implemented using an exception. The main difference between the Assert statement and exceptions is that the Assert statement stops program execution at the Assert statement line. An exception, on the other hand, is thrown when there is a problem and program execution starts rolling back until the first exception handler is found. The SC2-T1-1

[DBCInvariant("Valid Count", "(Count >= 0) && (Count <= Capacity)")] public interface IStack { [DBCEnable(InvariantDisabled=true)] int Capacity { get; } [DBCEnable(InvariantDisabled=true)] int Count { get; } [DBCEnsure("Result Matches Count", "result == (Count == 0)")] bool IsEmpty { get; } [DBCEnsure("Result Matches Count", "result == (Count == Capacity)")] bool IsFull { get; } [DBCRequire("Not Empty", "! IsEmpty")] object Top { get; } [DBCRequire("Not Full", "! IsFull")] [DBCEnsure("New Top", "! old IsFull implies Top.Equals(value)")] [DBCEnsure("New Count", "! old IsFull implies Count == old Count+1")] void Push( object value ); } [DBCRequire("Not Empty", "! IsEmpty")] [DBCEnsure("New Count", "! old IsEmpty implies Count == old Count-1")] void Pop(); exception provides a graceful way of handling and correcting errors. In addition to, or instead of, passing a Boolean value to the enable attribute, one or more of the properties of the enable attribute can be used. Each contract assertion type has three properties; assertiontypeassert, assertiontypeexception and assertiontypedisabled where assertiontype is PreCondition, PostCondition or Invariant. The Capacity and Count properties in Figure 1 show that the invariant assertions are disabled for these properties only. 2.2 Building With extensible C# Once the contract is specified using attributes, which is stored in the metadata, there needs to be a way of getting the contracts into the code. To do this, Resolve Corp. s extensible C# add in [9] is used. extensible C# is a program that integrates with Microsoft s Visual Studio development environment. When it is enabled, the add in waits for the development environment to successfully build an assembly and then injects code into the assembly based on specific attributes. The add in allows users to all additional attributes to its set of predefined attributes which is what the authors of this paper did. The technique used by the extensible C# add in to inject code into the assembly is as follows: 1. Process each type (class, structure) in the assembly. 2. Process each member (method, property) in each type. Figure 1. Sample C# stack interface with contracts. 3. Get the attributes associated with the member and inject code into the member. The first step of the process is handled by the add in and is not accessible to the writers of custom attributes. However, the authors of this paper handle the second and third steps of the procedure. There are two places that the design by contract assertions gets injected into methods or properties. The first place is before the first statement of the method or property as defined by the source code. The second is at any return statement, or in the absence of a return statement, after the last statement of the method or property as defined by the source code. Pre condition assertions and the storing of values specified by the old keyword of post condition assertions are placed at the beginning of the method or property. Also, if the method or property is non private and is not a constructor, invariant assertions are placed at the beginning of the method or property. Post condition assertions, and if the method or property is non private, invariant assertions are placed at the end of the method or property or at each return statement. When a return statement is encountered it is replaced with a new block of code. This block of code first stores the value being returned in a result keyword variable. Next any post condition and invariant assertion code is added. Finally, the stored result value is returned. 3. Inheritance Another of the basic principles of design by contract is that a class inherits its contracts from its base class. This should not be SC2-T1-2

surprising for anyone familiar with object oriented programming since a class inherits its members and functionally from its base class. There are a few simple rules that must be followed when changing a contract in a derived class. The first is that when a subclass modifies a pre condition, it can only weaken the assertion to make it less restrictive. The weakening of a condition can be viewed as logically OR ing the conditions. The second is that when a subclass modifies a post condition or invariant, it can only strengthen the assertion to make it more restrictive. The strengthening of a condition can be viewed as logically AND ing the conditions. Since the post conditions and invariants can only be strengthened, the authors of this paper did not need to anything to enforce this requirement. That is because in a strengthened condition, all parts of the condition must pass the assertion check. Checking each part of the condition separately is equivalent to checking each part of the condition AND ed together. On the other hand, since pre conditions can only be weakened, the authors of this paper needed a way of enforcing this requirement. The technique used is to combine all pre conditions for a given method or property that have the same label using the logical OR operator. 3.1 Inheritance in C# C# only supports single inheritance, but it allows a class to implement multiple interfaces. An interface defines a type that has methods and/or properties, but does not have any executable code. When a class implements an interface, it implements all the methods and properties defined in the interface. The class designer has a choice when implementing each method and property of an interface. The class designer can choose to directly implement the method or property so it is accessible from both the class reference and the interface reference. The class designer can alternatively choose to implement the method or property so that it is only accessible from an interface reference. When a class implements an interface, the class is also bound by the contract defined in the interface. This means that all pre conditions and post conditions on methods and properties defined in the interface apply to the class implementation of those methods and properties. Also, all invariants defined in the interface become invariants of the class. But what happens when a class implements two interfaces that share a common method? The answer is it depends on how the class implements the common method. If the class uses a single implementation of the method for both interfaces, then the pre conditions and post conditions from both interfaces are applied to the class method. If the class uses separate methods for each interface method, then only the pre conditions and post conditions from the proper interface are applied to the class method. 4. Test Cases In order to properly determine whether or not contracts can be used in C#, a set of test cases were developed. The test cases were designed to exercise the capabilities of design by contract in a variety of structural situations. Several of the test cases were taken from the examples provided by [6] and adapted for the C# language. The first test case (TC1) used a single class that defined a contract. The second test case (TC2) used an abstract base class that defined a contract and two derived classes. The first derived class simply used the contract inherited from the abstract base class. The second derived class used the contract inherited from the abstract base class and modified the contract for two methods, making the second derived class easier to use. The third test case (TC3) used an interface that defined a contract and two classes that implement the interface. As in TC2, one class used the contract from the interface without modification and the second class made modifications to the contract. The fourth test case (TC4) used multiple interfaces, each defining their own contract, and a single class that implemented both interfaces. The interfaces did not have any methods or properties in common. The fifth test case (TC5) used multiple interfaces that shared a common method. Two classes implemented both interfaces where the first class used a single method to implement the common interface methods and the second class used two methods to implement the common interface methods. Finally, the sixth test case (TC6), in order to get more than one level of inheritance, used an interface that defined a contract, an abstract class that implemented the interface and modified the contract and a derived class the inherited from the abstract class. While compiling TC5, a minor problem was encountered. The two interfaces had a method in common and the class implemented the common method using separate methods. However, when this is done, the method is not accessible when using a reference to the class; it is only accessible using a reference to the interface. Since the interface defined the contract using the method and property names only, this is seen by the compiler as going through the class reference. And since the method common to both interfaces is not accessible through a reference to the class, the compiler generated errors. The solution was to modify the way the interfaces defined their contracts. Instead of using a property or method name directly, the name needed to be qualified as being part of the interface. As an example, the expression from the ISet interface changed from to Has(value) ((ISet) this).has(value) this in C# is a keyword for the reference to the class. It is then cast to be a reference to the interface. Another issue that appeared during development was a stack overflow when invariants were part of the contract. By definition, invariants are to be checked before and after every non private method or property. This includes the methods and properties that are used by the invariant assertion checks. Since the assertion checks are implemented by injection code into the methods and properties, there is no way to ignore the checks when a method is entered multiple times. This is what caused the stack overflow problem. To get around the problem, the invariant checks are disabled for the methods and properties involved in the checks by using the DBCEnable attribute. 5. Test Procedure and Results In order to test the effectiveness of design by contract in C#, a combination of methods was used. First, a test program was used to exercise the above test cases. The test program was used as a general check of the test cases and the pre conditions. Also, with SC2-T1-3

changes to the test cases, the post conditions and invariants were also checked. This verified that the contracts were properly being enforced. The second test of effectiveness used a.net decompiler tool. This tool reads an assembly s intermediate language (IL) byte codes and displays the information in a human readable format. This tool was used to verify that the proper assertion checks were being placed in the proper locations within the assembly. As defined in the source code, there were a total of 13 invariants, 30 pre conditions or which 4 were redefinitions and 61 post conditions. After the assertion checks were converted to executable code, there were a total of 20 invariants, 38 pre conditions and 87 post conditions. The second set of numbers is larger because there are several classes that inherited contracts. As seen in Table 1 and Table 2, all of the contract assertions that were defined in interfaces and all of the contract assertions that were defined in abstract base classes made it into the derived classes, with two notable exceptions discussed in the next paragraph. Also, any contract additions or modifications also made it into the derived classes. In TC2 and TC6, the abstract class defined a post condition on its constructor. These post conditions were not inherited by the derived classes because in C# a derived class cannot inherit a constructor. Instead, a derived class constructor calls a base class constructor before executing any code in the derived class constructor. This means that any post conditions defined in a base class constructor must be satisfied before any code from the derived class constructor is executed. However, with proper class design of encapsulation, this is normally not a problem. Table 1 Contract assertions as defined in source code ( in TC2 and TC3 redefine 2 pre-conditions). TC1 TC2 TC3 TC4 TC5 TC6 2 2 Invariants 3 1 0 0 1 0 0 2 2 0 2 2 0 0 0 0 0 Pre Conditions 4 2 0 2R 2 0 2R 2 2 2 2 2 2 2 4 0 0 Post Conditions 15 6 0 2 5 1 3 4 2 2 5 3 2 2 5 4 0 Table 2 Contract assertions as seen in executable code. TC1 TC2 TC3 TC4 TC5 TC6 2 2 Invariants 3 1 1 1 0 1 1 0 0 4 0 0 4 4 0 0 0 Pre Conditions 4 0 2 2 0 2 2 0 0 6 0 0 6 6 0 4 4 Post Conditions 15 1 5 7 0 6 8 0 0 8 0 0 10 10 0 9 8 6. Summary This paper described a technique of adding contracts to C#. Custom attributes are used to specify the pre conditions (DBCRequire), post conditions (DBCEnsure) and class invariants (DBCInvariant). Also, a fourth attribute (DBCEnable) is used to specify the types of assertion checks and how the checks are implemented. These attributes are injected into the executable code using Resolve Corp. s extensible C# add in. This implementation of design by contract supports contracts across class hierarchies as well as interfaces. The use of the old keyword is supported for post conditions to compare values from the before the method or property was called and after the method or property is done executing. Also, the use of the implies keyword is supported for post conditions to conditionally check the assertion. 7. Future Work One area of work to be investigated is how to solve the contract recursion problem. Ideally, all of the public methods and properties that have contracts call private methods and properties to do the actual work while the public versions check the contract. Then the contract assertions could call the private methods and properties, thereby eliminating the recursion. However, this is not possible using the extensible C# add in. SC2-T1-4

8. REFERENCES [1] P. Guerreiro, Another mediocre assertion mechanism for C++, 33rd International Conference on Technology of Object-Oriented Languages, 2000. TOOLS 33. Proceedings, June, pp 226-237, 2000 [2] R. Kramer, icontract the Java design by contract tool, Technology of Object-Oriented Languages, 1998. TOOLS 26. Proceedings, Aug, pp 295-307, 1998 [3] K. McFarlane, Design by Contract Framework, [Online document] July 1992, [2004 Oct. 18] Available at HTTP: http://www.codeproject.com/csharp/designbycontract.asp [4] B. Meyer, Applying design by contract', Computer, Oct., pp 40-51, 1992. [5] C. Mingins and C. Chan, Building Trust In Third-Party Components Using Component Wrappers In The.NET Frameworks, Proceedings of the Fortieth International Conference on Tools Pacific, 2002, pp 153-157 [6] R. Mitchell and J. McKim, Design by Contract, by Example, Indianapolis, Indiana: Addison Wesley, 2002 [7] J. Newmarch, Adding contracts to Java, Technology of Object-Oriented Languages, 1998. TOOLS 27. Proceedings, Sep, pp 2-7, 1998 [8] N. Tran; C. Mingins; D. Abramson, Design and implementation of assertions for the Common Language Infrastructure, Proc. IEE Software, vol 150, no. 5, Oct., pp 329-336, 2003 [9] extensible C# [Online document], [2004 Oct. 18] Available at HTTP: http://www.resolvecorp.com/xcsharp.ppt SC2-T1-5