12 Chapters 2 & 6 A Method for Support for Design By Contract on the .NET platform Andreas Sjögren Department of Computer Science Mälardalen University Västerås, Sweden andreas.sjogren@mdh.se Abstract: It is widely acknowledged that semantic information about a component's operations is needed to use a component effectively. There is clearly a need for more formal specifications methods for components. However, generally there is a gap in software engineering between formal specifications and practical applications of these. Techniques based on Design By Contract are very useful for ComponentBased Systems, and at the same time quite simple to understand and use. In this paper we discusses different practical implementations and models for support for Design By Contract in Object-Oriented Programming Languages and Component-Based Development. We also present a proposal for a method to provide support for Design By Contract for components on the .NET platform, implemented in any .NET programming language. Component interfaces can be specified in UML, with invariants, pre- and post-conditions, which later can be evaluated during runtime. We use the attributes of the .NET platform to implement specifications, since the attributes of a component are provided as metadata during runtime and thereby provide possibilities for monitoring violations to the assertions. 1 Introduction Reliability is today a very important concern in the software industry. Reliability is a system's ability to perform its job according to the specification (correctness) and to handle abnormal situations (robustness). Reliability is extra important with component software because of the focus of reusability and off-the-shelf components. Unless we can obtain reusable software components whose correctness we can trust much more than we trust the correctness of usual software, reusability is unlikely to succeed. It is well known how to specify a component interface on the syntactic level, but for semantic specifications practical approaches are rare. CBSE is still lacking, as all software engineering disciplines, in many sense in the connection between existing formal methods and the practical application of these. To ensure that component software will perform properly we need a useful, systematic approach to specify, implement and verify components and their relations in a system. This paper discusses a method for this, called Design By Contract (DBC) [1]. Under the DBC theory, a software system is viewed as a set of communicating components whose interaction is based on contracts, precisely defined specifications of the mutual obligations. In Section 2 we will discuss the basic concepts of DBC. In Section 3 we explore different methods and practical implementations for providing support for Design By Contract. In Section Andreas Sjögren: A Method for Support for Design By Contract on the .NET platform Extended Report for I. Crnkovic and M. Larsson (editors), “Building Reliable Component-Based Systems”, Artech House, July 2002, ISBN 1-58053-327-2: Chapter 2: Specification of Software Components, F. Lüders, K.-K. Lau, S.-M. Ho Chapter 6: Semantic Integrity in Component Based Development, E. J. Nordby, M. Blom Chapters 2 & 6 13 4 we present a method for supporting these mechanisms and providing a way to monitor violations to the constraints during runtime. In Section 5 we discusses future work on the method discussed in Section 4. Finally, in Section 6 we summarize the paper. 2 Design By Contract Bertrand Meyer from Interactive Software Engineering (ISE) developed Design By Contract as a part of the object-oriented programming language Eiffel [1,2]. The DBC theory associates a specification with every software element. These specifications, called contracts, describe the interaction of the components with the rest of the world. It is a general valuable design technique, which provides an effective framework for debugging, testing and, more generally, quality assurance, and it also gives additional documentation about the software components. In this model the relationships between a client and a supplier are viewed as a contract that takes the form of assertions, as boolean invariants, pre-conditions and post-conditions. The preconditions are the contractual obligations a client must satisfy. In Eiffel the notation for this is require. The post-conditions are the contractual obligations the supplier ensures to fulfill. In Eiffel the notation for this is ensure. The invariants constrain all services of all instances of the supplier. In Eiffel the child classes automatically inherits all the assertions from the parents. A method re-declaration may keep or weaken the pre-conditions, and it may keep or strengthen the post-conditions. Here is an example of a method push for a class Stack in Eiffel, pushing an element has the pre-condition that the stack is not full before the invocation and the postcondition that the top element will be the top element of the stack after the invocation (the implementation uses some methods of the class which is not presented, but there usage are quite obvious): push (x:T) is require not full do –-push element v of type T to the stack –-pre-condition that the stack is not full -- ..the pushing algorithm.. ensure not isEmpty –-the stack cannot be empty afterwards getItem = x –-the pushed element is the top on the stack end The question of what will happen when one of these conditions fails during execution is depending on whether the assertions are monitored during runtime and is not a question of the actual design technique. A runtime violation of an assertion is always a manifestation of a software bug [1]. A pre-condition violation indicates a bug in the client and a post-condition violation a bug in the supplier. When talking about contracts in CBSE we mean interface contracts, and Bachman, et al, argues in [3] that contracts shift the focus of specification of components to a specification of patterns of interactions. DBC is very well suitable for specifying interactions, and thereby for specifying components. 3 Implementations of Support for Design By Contract In this section we will explore some other practical implementations and suggested methods for support for DBC for Object-Oriented and Component-Based Systems. Andreas Sjögren: A Method for Support for Design By Contract on the .NET platform Extended Report for I. Crnkovic and M. Larsson (editors), “Building Reliable Component-Based Systems”, Artech House, July 2002, ISBN 1-58053-327-2: Chapter 2: Specification of Software Components, F. Lüders, K.-K. Lau, S.-M. Ho Chapter 6: Semantic Integrity in Component Based Development, E. J. Nordby, M. Blom 14 Chapters 2 & 6 In principle we can identify five different methods of using DBC in a programming language or environment, which does not support the theory from the beginning. The first alternative, is simply add comments in a structured fashion which provides contracts for functions or classes, but this is not very useful since we want to have executable contracts which can be monitored during runtime. A better approach is to use either formal comments or special macros and run the code through a preprocessor, for instance by using a tool, which both adds the macros and runs the preprocessor. This notion somewhat relates to the assert macro in the programming languages C and C++, which takes an expression and an error message. If the expression is false it writes the message and terminate the execution. Another alternative is to add new mechanism to the programming language itself. This is of course in many senses the best alternative, but it is often not that easy done and sometimes not even possible. The fourth alternative is to use a library approach where we add functions for supporting the DBC mechanisms, and suggests conventions that must be followed for calling functions. The last identified alternative is to use a tool, which makes is possible to write the contracts in another language, which supports DBC (e.g. Eiffel) and then transforms the code to legal code for the original language. Often implementation of these techniques for providing DBC has (as for Eiffel itself) the disadvantages of the dependence of one particular programming language. 3.1 Contracts in Java There exist several models for adding contracts to the Java programming language. One example is the freely available iContract tool [4], which uses a preprocessor to generate Java Code with contracts. The contracts are added as JavaDoc comments. The tool converts the comment tags into assertion check code. The contracts has the following structure: /** * @pre <expr> #ExceptionName * @post <expr> * @invariant <expr> */ ExceptionName is the name of the exception to be raised if the assertion is violated. The expressions in iContract are modeled after a own specification language, which is a subset of the Object Constraint Language (see Section 3.5). The benefit of using contracts as comments is the non-mandatory nature of these. The code with contracts remains completely compatible with Java and can be processed with all Java implementations. This model provides a way of applying DBC with monitoring in Java, but it will not allow switching contract checking dynamically. Another model for Java is jContractor [5]. This is a purely library based approach which together with a set of conventions support DBC in Java. I this solution it is possible to write the contract in ordinary Java syntax. The contracts are specified in methods in a class definition following the naming conventions. jContractor checks for these patterns in class definitions and rewrites the classes on the fly. The approach takes advantage of the Java reflection API for automatically adding assertions to the original methods. The advantage with this approach is that it works with any Java implementation and does not require any special tool. Andreas Sjögren: A Method for Support for Design By Contract on the .NET platform Extended Report for I. Crnkovic and M. Larsson (editors), “Building Reliable Component-Based Systems”, Artech House, July 2002, ISBN 1-58053-327-2: Chapter 2: Specification of Software Components, F. Lüders, K.-K. Lau, S.-M. Ho Chapter 6: Semantic Integrity in Component Based Development, E. J. Nordby, M. Blom Chapters 2 & 6 3.2 15 Contracts in Python Reinhold Plösch at Johannes Kepler University, Linz, has integrated DBC in the interpreted object-oriented language Python [6]. In this solution the DBC concepts are added without changing the language. Like for iContract the assertions are specified in comments by using the keywords req, ensure and inv. Then a modified interpreter provides methods for parsing and runtime check of the assertions. 3.3 Contracts in C++ There exist several models for adding contracts to the C++ programming language. An example is a high level system developed at Johannes Kepler University, Linz, which is based on the implementation of contracts for Python discussed in the previous section. This system transforms Python assertions into C++ code. A parallel check class is generated for every ordinary class. The check class contains methods fore assertion checking. This system has a lot of technical problems in the transformation from Python classes to the C++ classes and the usage of two different programming languages can also been considered a problem with this approach. Another example is presented in [7]. Here all classes have to inherit from a class called Assertions, which provides the needed mechanisms. Here is a simplified version of the Assertion class: class Assertions { public: class Exception: std::exception { public: Exception(const std::string& l):exception(“Assertion violation:”+l) {} }; //pre-conditions virtual void require(bool b, const std::string& label) const { if (!b) throw Assertions::Exception(“require” + label); } //post-conditions void ensure(bool b, const std::string& label) const { if (!b) throw Assertions::Exception(“require” + label); if (!invariant()) throw Assertions::Exception(“invariant” + label); } //default invariant virtual bool invariant() const { return true; } } An implementation of a method push of a class Stack which uses the require and ensure methods will look like: Andreas Sjögren: A Method for Support for Design By Contract on the .NET platform Extended Report for I. Crnkovic and M. Larsson (editors), “Building Reliable Component-Based Systems”, Artech House, July 2002, ISBN 1-58053-327-2: Chapter 2: Specification of Software Components, F. Lüders, K.-K. Lau, S.-M. Ho Chapter 6: Semantic Integrity in Component Based Development, E. J. Nordby, M. Blom 16 Chapters 2 & 6 virtual void push(const T& x) { require(!isFull(), “not full”); // ..do the push stuff.. ensure(!isEmpty(), “not empty”); ensure(getItem()==x, “top element”); } The class Stack can have the following invariant: virtual bool invariant() const { return 0 <= getCount() && getCount() <= capacity(); } If we want to handle violations to the assertions we have to catch the exceptions and take the proper action. 3.4 Contracts on the .NET Platform The easiest way to be able to use contracts on the .NET platform is to use the .NET version of Eiffel. But of course all people are not likely willing to change the programming language to Eiffel. Arnout and Simon from ISE propose in [8] a tool they call the Contract Wizard. This tool adds a possibility to define contracts for existing Assemblies to the .NET framework [9], independently from the .NET language it was written in. In the toll a user can write invariants, pre- and postconditions as Eiffel expressions. The Wizard then generates Eiffel classes with the specified contracts and calls an Eiffel compiler to generate new Assemblies with contracts, see Figure 1. For the moment there is a discussion going on if the Contract Wizard is to be added to the main release of Visual Studio.NET by default. One problem with this approach is that we still need to have an existing Eiffel environment. As far as we understand it, another problem is that if you are using another language than Eiffel you cannot add contracts to the components during the design phase or the implementation, this has to be done in a separate phase after the actual implementation of the components. Figure 1. Generation of .NET assemblies with contracts. 3.5 Using Contracts in the Design Phase To use contracts in the design phase of components we can use a specification language. There exist different specification languages for specifying invariants, pre- and post-conditions. One example is the object constraint language (OCL) [10], which is a part of the UML standard [11]. OCL is a textual language that allows construction of logical expressions. The purpose of OCL is only to improve the precision of a UML specification. Andreas Sjögren: A Method for Support for Design By Contract on the .NET platform Extended Report for I. Crnkovic and M. Larsson (editors), “Building Reliable Component-Based Systems”, Artech House, July 2002, ISBN 1-58053-327-2: Chapter 2: Specification of Software Components, F. Lüders, K.-K. Lau, S.-M. Ho Chapter 6: Semantic Integrity in Component Based Development, E. J. Nordby, M. Blom Chapters 2 & 6 17 Cheesman and Daniels [12] describe how components can be specified in an extended UML version and OCL with contractually specified interfaces. Here the contracts consist of invariants, pre-conditions, post-conditions and intra interface constraints. They distinguish between two types of contracts: 1. Usage – the contract between an component’s interface and its clients 2. Realization – the contract between a component specification and its implementation The primary reason for keeping these things separate is to facilitate change. A change to the realization constraints does not affect clients. This is important because it gives the ability to change specifications that effect realization without having to change all client usage. This method is used as a part of the method discussed in next section. To understand the (very important) details of the first part of this method we have to understand the method in [12], in particular the extended things in UML. For the sake of this paper we will not, because of space and time limits, discuss this any further. 4 UML Contracts Specifications for Components on the .NET Platform Our method for designing components according to the DBC technique and providing a way of monitoring and dynamically adding ways of handling violations to the assertions using more or less standard methods and tools. We have chosen to use the model with UML and OCL from [12] for specifying components. The need to use another language for specifying the contracts than for the implementation of the components approach can be considered to be a drawback of the method. However, the whole idea is to provide a way of design components with contracts, which is not depending on any particular programming language. Since OCL is a part of the UML standard this is a standard specification language and it should be easy to find tools that support the language. Unfortunately, for the moment there are few commercial UML tools that have support for OCL despite it is a part of the UML standard. However, it is still easy to get documentation for it and there are freely available parsers for it. The approach with OCL does not necessary have to exclude other languages. Since we attempt to use a “componentized” structure of the whole method we hope to be able to switch the specification language to another language if so is desirable. The specifications will have an abstract state model connected The components can then be implemented in any .NET programming language. The .NET platform provides possibilities for monitoring violations to the assertions during runtime. In the .NET framework there is support for a mechanism called attributes [9]. Using attributes on components is a way to provide meta data. .NET makes is possible to create own customized attributes by implementing a class which derives from the System.Attribute class. Using .NET attributes give good support for implementing specifications for components. Attributes can be attached to components, interfaces or methods. This feature can be utilized to implement the assert expressions, invariants, pre- and post-conditions. An invariant attribute can only be attached to a component and the invariant must hold true during the whole execution of the component. Andreas Sjögren: A Method for Support for Design By Contract on the .NET platform Extended Report for I. Crnkovic and M. Larsson (editors), “Building Reliable Component-Based Systems”, Artech House, July 2002, ISBN 1-58053-327-2: Chapter 2: Specification of Software Components, F. Lüders, K.-K. Lau, S.-M. Ho Chapter 6: Semantic Integrity in Component Based Development, E. J. Nordby, M. Blom 18 Chapters 2 & 6 Each time a component is compiled into the Microsoft intermediate language (IL) and stored in the portable executable (PE) format, the attributes are stored as metadata. This meta data can then be programmatically be retrieved when needed, for example, during execution of the component. 4.1 Implementation Ideas We have designed three different types of attributes, one for each type of condition that we want to check during runtime. The invariant attribute can be only be used on components or classes that have states, while pre- and post-condition attributes can be attached to methods of an interface or component. Here is a simple example of an implementation in C# of the attribute for a precondition (the example only shows how the attributes are used to provide the syntactic possibility of adding pre-conditions): //attribute class for precondition attributes [AttributeUsage(AttributeTargets.Method)] public class PreConditionAttribute: System.Attribute { public PreConditionAttribute(string expression) { m_Expression = new OCLExpression(expression); } public OCLExpression m_Expression; } //class for OCL expressions public class OCLExpression { public OCLExpression(string expression) { m_OCLExpression=expression; } public string getExpression() {return m_OCLExpression;} private string m_OCLExpression; } To enable the possibility of using another specification language than OCL we can later simply change the OCLExpression component to a more generic expression component. If attributes are attached to an interface they will operate in the input and output parameters. The attributes can manually be added to components or via an UML tool. The usage of the attributes for a method f of a class C will look like: [ invariant <expr> ] class C { [ precondition <expr> ] [ postcondition <expr> ] f(); } The biggest problem, and maybe the most interesting part (although not mentioned much here) of the method, is the problem of providing the mapping of the abstract state model in the specification to a concrete state model in the implementation. Without this mapping the mechanisms for adding pre- and post-conditions to the code will not be much meaningful. Andreas Sjögren: A Method for Support for Design By Contract on the .NET platform Extended Report for I. Crnkovic and M. Larsson (editors), “Building Reliable Component-Based Systems”, Artech House, July 2002, ISBN 1-58053-327-2: Chapter 2: Specification of Software Components, F. Lüders, K.-K. Lau, S.-M. Ho Chapter 6: Semantic Integrity in Component Based Development, E. J. Nordby, M. Blom Chapters 2 & 6 4.2 19 Exception Management To be able to have multiple strategies what to do when a condition does not hold we can introduce exception components. An application can specify what exception strategy it wants to use by attaching one of these exception components. Examples of different of actions to be taken when an exception is raised are: • Throw an exception • Write a log entry in a logging tool • Shutdown or abort application • Ignore But how to exactly handle this is up to the user and beyond the scope of this work. We will only provide the plug-in mechanism for client components for handling violation to the assertions. 5 Future Work There are a lot of things to work on with the method. We are still not sure what exactly we want to do. There are some different possible tracks to take. We can in next step choose to concentrate more on the part of designing component in UML with OCL specified contract (through some existing tool or a modification of an existing tool) and generate the OCL attributes automatically for the objects. Another possibility is to code the OCL expressions manually and concentrate more on the monitoring mechanism. We have investigate and run some test for how exactly we shall get the needed information to monitor violations to the assertions. We have to precisely define the mapping mechanisms for the mapping between the abstract state model in the specification and the concrete state model of the implementation. We have also to do further investigation on related work on DBC for the component world. For instance, DBC is applied to components in the Catalysis method [13], we have to look up more what have been done here. 6 Summary We have in this paper discussed briefly the basic properties and needed mechanisms of Design By Contract. Further, we have presented some practical implementations of these techniques. We presented a proposal for a method with support for DBC and runtime monitoring of the constraints of components based upon existed techniques. Since we using a standard language in form of UML and OCL for specifying the components and implementing them on the .NET platform, which probably going to be a well used platform in the coming years, there is a chance that this method can help to bridging the gap between the (semi) formal method and the practical application of this method. Andreas Sjögren: A Method for Support for Design By Contract on the .NET platform Extended Report for I. Crnkovic and M. Larsson (editors), “Building Reliable Component-Based Systems”, Artech House, July 2002, ISBN 1-58053-327-2: Chapter 2: Specification of Software Components, F. Lüders, K.-K. Lau, S.-M. Ho Chapter 6: Semantic Integrity in Component Based Development, E. J. Nordby, M. Blom 20 7 Chapters 2 & 6 References [1] Meyer B., Applying Design by Contracts, IEEE Computer, volume 25, issue 10, 1992. [2] Meyer B., Eiffel: The Language , Prentice Hall, 1992. [3] Bachman, F., Bass, L., Buhman, S., Comella-Dorda, S., Long, F., Seacord, R. C., and Wallnau, K. C., Technical Concepts of Component-Based Software Engineering, report CMU/SEI-2000-TR-008, Software Engineering Institute, Carnegie Mellon University, 2000. [4] Kramer R., “iContract - The Java Design by Contract Tool”, In Proceedings of Technology of Object-Oriented Languages, TOOLS26, IEEE Computer Society, 1998. [5] Karaorman M., Hölze U., and Bruno J., “jContractor: A Reflective Java Library to Support Design by Contract”, In Proceedings of Metal-Level Architectures and Reflection, Lecture Notes in Computer Science, nr 1616, Springer Verlag, 1999. [6] Plösch R., “Design by Contract for Python”, In Proceedings of Asic Pacific Software Engineering Conference, IEEE Computer Society, 1997. [7] Guerreiro P., “Another Mediocre Assertion Mechanism for C++”, In Proceedings of Technology of Object-Oriented Languages, TOOLS33, IEEE Computer Society, 2002. [8] Arnout K. and Simon R., “The .NET Contract Wizard: adding Design by Contract to languages other than Eiffel”, In Proceedings of TOOLS 39, IEEE Computer Society, 2001. [9] Thai T. and Lam H., .NET Framework, O´Reilly, 2001. [10] Warmer J. and Kleppe A., The Object Constraint Language, Addison Wesley, 1999. [11] OMG, OMG Unified Modeling Language Specification, report version 1.3, June 1999, OMG, 1999. [12] Cheesman J. and Daniels J., UML Components - A Simple Process for Specifying Component-Based Software, Addison-Wesley, 2000. [13] D’Souza D. and Wills A. C., Objects, Components and Frameworks: The Catalysis Approach, Addison Wesley, 1998. Andreas Sjögren: A Method for Support for Design By Contract on the .NET platform Extended Report for I. Crnkovic and M. Larsson (editors), “Building Reliable Component-Based Systems”, Artech House, July 2002, ISBN 1-58053-327-2: Chapter 2: Specification of Software Components, F. Lüders, K.-K. Lau, S.-M. Ho Chapter 6: Semantic Integrity in Component Based Development, E. J. Nordby, M. Blom