(a:=creale Account) = (a:---a'. a' ~ dora heap; var x:Account . heap[a]:=x). (y:=a/m(e)) ..... D.A. Carrington, D. Duke, R. Duke, P. King, G. A. Rose, and G. Smith.
On O b j e c t - O r i e n t e d D e s i g n and Verification C. Lewerentz, Th. Lindner, A. Riiping, E. Sekerinski Forschungszentrum Informatik Karlsruhe (FZI) Abstract. We present a theory of object-orientation on the basis of the refinement calculus. This theory allows for specifying the behaviour of objects and provides a calculus for the proof of relationships between classes such as refinement. Given two similar, but not identical classes, we present an algorithm to construct a common superclass which is refined by both classes, and an algorithm to construct a common subclass which refines both classes. As an example, we present an account manager to illustrate design and verification. The overall approach aims at giving a simple theoretical basis for incremental object-oriented software construction. We demonstrate how formal specification and verification can be integrated into the development process, and thus can be put into practical use.
1 Introduction Object-orientation supplies structuring constructs for software systems which are new, compared to traditional programming. These structuring constructs support a development process that smoothly integrates all stages of software development. Furthermore, object-orientation allows for locally developing single software components and thus increases the reusability of software. Formal methods provide mathematically precise description techniques and, on the basis of an appropriate calculus, make proofs of program correctness possible. Moreover, formal methods support abstraction in that they allow for describing what the behaviour of single components is rather than how it is implemented. The FZI contribution to the project KoRSo deals with the combination of objectorientation and formal methods. The formal semantics of object-oriented constructs is the prerequisite for their precise understanding and for their proper use. Furthermore, we embed formal methods in a software life cycle that is recognized to support the reuse of design, code, specification, and proofs.
Object-Oriented Refinement. The refinement calculus as developed by R. Back, C. Morgan, and J. Morris [BvW89, Mor90, Mor87] provides a semantics for imperative programming constructs by weakest preconditions. The programming language is extended by several kinds of nondeterminism (angelic and demonic) which are used for specification [BvW90]. The core of the calculus is the refinement relation for refining non-executable programs to executable code. A brief introduction is given in Section 2. We extend the refinement calculus by objects, object types and classes. Our approach differs from that of object-oriented specification languages like [CDD+90, LH92] in that it is not just an extension of an existing specification language. It
93 differs from the OOZE approach [AG91] since we aim at an imperative programming language and provide a refinement relation on both programs and classes. The calculus is presented in Section 3. Inheritance is an important feature of object-oriented languages. A new class is constructed by inheriting from existing classes. We distinguish inheritance as a syntactic means for constructing new classes from the semantic relation of refinement. Class refinement means that the observable properties of a class are preserved. It may hold between any classes with the same signature, independently of the way they are constructed. Class refinement or behavioural subtyping has first been studied by P. America [Ame87]. In this approach, as well as in newer ones like Z + + [LH92], class refinement is defined by a set of proof obligations. We extend this treatment by first giving a behavioural definition of refinement as done by T. Nipkow [Nip86], C. A. R. Hoare et al. [HJS87] for data types. From this, proof obligations can be derived which are similar to those of data refinement [BvW89]. This is done in Section 4. In object-oriented modelling one frequently has to integrate two similar, but not identical classes. It is convenient to have a superclass which factors out their common behaviour. The superclass provides common operations which preserve the semantics of the original operations. Thus, instead of writing, maintaining, and verifying the same operation twice, this is done once for the superclass. As a main contribution, this paper shows a constructive way how to obtain a common superclass which is refined by both subclasses. Analogously, there is a way to construct a class which refines both original classes. We show that the set of classes with the same signature together with the refinement relation form a lattice. Although not proved, our algorithm constructs both the "least refining class" and the "greatest refined class". We illustrate this with an example of two different kinds of bank account in Section 5.
Object-Iris and Modules. Object identity is considered to be an important issue in object-orientation. We define the usage of object identities in our framework. Next, we introduce modules that encapsulate cooperating classes. Several studies have expressed the need for structures that are less fine-grained than classes (cf. [Szy92, Wil91, AG91]). We demonstrate that modules support component-oriented specification and verification techniques in the presence of object identity. Also, modules allow for extending the notion of compatibility to groups of classes. This discussion is presented in Section 6. Problem analysis. Finding an initial formal specification is as difficult as refining this specification to code. Therefore, in order to put formal methods into industrial use, we find it necessary to integrate them into a software development life cycle model. This integration should be smooth, in that the transition from the informal to the formal should be easy, and should be flexible, in that the developer may choose whether and where to use formal methods. To achieve these goals we use Responsibility Driven Design [WBWW90], one of several object-oriented analysis and design methods [Boo91, Jac92, RBP+91], and adjust it to the integration of formal specification into the analysis and design process. A short overview of this method is given in Section 7.
94
2
A Brief Introduction
to the Refinement
Calculus
This section gives a brief introduction into the refinement calculus. The refinement calculus can be based on different models for non-deterministic programs. While programs can be defined in a simple way by predicates [Sek93], we choose to define programs by predicate transformers. This brings a b o u t the advantage that a lattice is set up by the set of programs together with the refinement ordering. The reader is referred to the standard literature for a more comprehensive and tutorial treatment [BvW89], [Mor90], [Mor87]. 2.1
Types, States, Predicates
Let . . . , x, y , . . . stand for variable names. W i t h each variable we associate a type. Let v be a list of variable names and T a list of types of equal length. A state over v : T is a mapping (partial function) from the variable names to values of the corresponding types. We write it as {vl ~ e l , . . . , vn ~-~ en}. If tr and v are states over disjoint variables, then tr + r is the union of both states. Furthermore, if x is a variable of state tr, then a[~ :--- el is state tr with e as the value of variable x, and tr - x is the state ~ without x. This is extended to lists of variables. A state predicate over v : T is a function from the states over v : T to the Boolean values Bool = {true, false}. For example, the expression x + y < z may be considered a state predicate over x, y : Int, Int. The variables x and y act as program variables, and the variable z as a logical variable (or constant). (Note that the expression alone does not suffice for making this distinction.) We use the usual Boolean connectives on state predicates. Universal equivalence of state predicates b, c is written as b = c, universal implication as b < c. 2.2
Predicate Transformers
Following Dijkstra, imperative programs can be given a semantics by predicate transformers which m a p postconditions to preconditions. More precisely, for lists v : T, w : U of variables, a predicate transformer p from v : T to w : U is a function from state predicates over w : U to state predicates over v : T. We call v : T ~ w : U the arity or type of p. If c is a predicate over w : U, and p is as above, then the functional application p c is the weakest precondition of p with respect to postcondition c, originally written as wp (p, c). Let b and c be state predicates over some variables v. Some basic predicate transformers from v to v are defined as follows.
abort c = false miracle c -- true skip c = c {b}c = b ^ c
[b]c = b ~ c
worst program best program identity program assertion: skip if b else abort assumption: skip if b else miracle
A state function from v : T to w : U is a function from states over v : T to states over w : U. The predicate transformer (f) is the counterpart to the state function
95
f which carries out a certain state change. It allows for expressing a d e t e r m i n i s t i c s t a t e change where the initial and final state spaces do not have to be identical. Let cr be a state over v : T. ( f ) c = (,kcr 9 c(fcr))
update
A conventional (multiple) assignment y :-- e changes the variables y of the s t a t e to e and leaves all others unmodified. The variable introduction e n t e r y : = e extends the initial state by variables y with initial values e. The variable elimination exit y removes the list y of variables from the state. They all can be defined by the u p d a t e . (y : = e) = ( ~ r . a[y := el) ( e n t e r y : = e) = ( h a . a + {y ~ e}) exit y = (A~r 9 a - y)
assignment variable introduction variable elimination
Let q be a predicate transformer from z : s to v : t. Furthermore, let I be an a r b i t r a r y index set and assume t h a t c does not depend on i E I . (q; p)c = q(p c) ([qi E I 9 p i ) c = (Vi E I 9 Pi c) (Ui E I 9 pi)c = (3i E I 9 Pi c)
sequential composition demonic choice angelic choice
Writing the choice between two programs by an infix operator, p l Mp2 establishes a postcondition c only if both p l and p2 do so. If either fails, so does the whole choice, hence it is demonic. Dually, p l t_lp2 establishes a postcondition c if either p l or p2 does, so the choice is angelic. T h e nondeterministic assignment y := y' 9 b chooses d e m o n i c a l l y a value y~ such t h a t b holds and assigns it to y. If no such value exists, it behaves as miracle. T h e local variable declaration is defined as a sequence with a variable i n t r o d u c t i o n , followed by the body of the block, and an elimination of the variables. (if b t h e n p e l s e q) = ([b]; p) ~ ([-%]; q) (y := y' 9 b) = (My' 9 [b]; y : = y') ( v a r y := e 9 p) = (enter y := e;p; exit y)
conditional nondet, a s s i g n m e n t variable declaration
For readability we often include the type in the declaration, writing v a r y 2.3
: T := e.
Algebraic Laws
Two predicate transformers p and q are equivalent, in s y m b o l s p = q, if a n d only if they are equal as functions,(Vc 9 p c = q c). From the definitions given above, we can derive a number of simple laws. We give them here without proofs, as t h e y are either straightforward or can be found in the literature. Let p, q, r be p r o g r a m s of a p p r o p r i a t e type. skip ;p = p; skip = p (p; q); r = p; (q; r) ( e n t e r z := d; enter y := e) = ( e n t e r z, y := d,e) ( e n t e r y := e; exit y) = skip ([7i E I 9 pi); q = ([qi E I 9 Pi; q) ( l i t E I 9 pi); q = (11i E I 9 Pi; q)
skip unit o f " " ";" associative enter seq. enter-exit cancel. ";" left distrib, over '~q" ",'" left distrib, over ~ "
96 2.4
The Refinement Ordering
A predicate transformer p is refined by a predicate transformer q of the same type, written p E q, if, whenever p can establish some postcondition, so can q. Hence everything p does can also be done by q, and we can use q instead of p. (p E q) r
(Vc- p c bal end F i n d i n g a common refinement of several classes is a typical design situation. This situation is problematic since it is unclear whether such a c o m m o n refining class exists and how it should look like. Using the construction for upper b o u n d s on classes we can always give a common refining class of two classes of the same type. However, this class may t u r n out to be miraculous or angelically nondeterministic. Let us calculate an upper b o u n d of SavingAccount and C u r r e n t A c c o u n t :
SavingAccount U C u r r e n t A c c o u n t definition and renanaing class
sbal, cbal : Real, Real := 0.0, 0.0, transact(amount : Real) = ({sbal + amount > 0}; sbal := sbal + a m o u n t ) U (cbal := cbal + amount)
104
balance() amount : Real = amount := sbal tJ amount := cbal, payinterest 0 = sbal :-:" sbal * Rate I1 skip end Upward Simulation Theorem with sire = enter sbal, cbal := bal, bal; ezit bal class bal : Real := 0.0, transact(amount : Real) = bal := bal + amount, balance() amount : Real = amount := bal, payinterest 0 = bal := bal . Rate II skip end Hence an upper bound is an account which allows overdraft and angelically decides whether to pay interest or not. Obviously, this account cannot be refined into executable code. This shows that there is no common subclass that could implement the behaviour of SavingAccount together with the behaviour of CurrentAccount. To define a class VariableAccount that allows for overdraft and pays interest, the class hierarchy has to be restructured such that appropriate abstractions of the particular accounts are provided.
7 7.1
Object
Identity
and
Modules
Object Identity
Objects are often provided with unique identities. Motivated by the object-oriented paradigm which considers objects to be autonomous entities, there is a common need for characterizing objects by their identity rather than by their state or value. Object identity is often expressed by references to objects. In addition to incorporating the object-oriented paradigm, applying references to objects also brings up the advantage of allowing for cyclic reference paths which typically occur in objectoriented systems. In the calculus presented above, object identity is expressed as follows. We assume that there is an implicit global variable v a r heap: m a p p i n g Id t o Object which yields to each identifier the corresponding object. Id is an unbounded set of identifiers. Creating a new object means adding a new entry to heap, and referring to an object via its identifier means applying heap to the identifier. The semantics for using objects with identities is explained with the following example: (var a:Id. p ) = (var a:Id:=nil, p) (a:=creale Account) = (a:---a'. a' ~ dora heap; v a r x:Account . heap[a]:=x) (y:=a/m(e)) = (var x:---heap[a]; y:=x.m(e); heap[a]:=~)
105
First, a variable declaration for an identifier is required. Next, a new account is created and is assigned to tl~e appropriate position in heap. Calling a method of an object known via its identifier is now defined as applying this method to the object that heap maps the identifier to. With the above definitions we are able to specify the accounts of a bank and the transaction of a certain amount as follows. A bank is specified as a mapping from account numbers to accounts: v a t bank: m a p p i n g AccountNo t o Id A transaction is specified by the following procedure:
read(accountno); read(amount); if accountno E dom bank t h e n bank[accountno]/transact(amount} else write(error) Without using object identities, we would have to introduce an additional variable of type Account, initialize it to be a copy of bank[accounlno], apply the withdrawal to this variable, and finally assign the updated value to bank[accountno]. Since the solution with object identity allows for directly invoking the method of an object, it is, in this case, more intuitive and elegant. However, the mapping heap being global, it makes it possible for every object to refer to any other object of the system. Thus, the concept presented for object identity allows for referring to objects in an object-oriented fashion, but makes modular specification and verification difficult. One approach to overcome this problem is to restrict the usage of object identities. 7.2
Modules
We introduce modules into the specification of object-oriented systems. Modules encapsulate cooperating classes whose objects have to refer to one another (cf. [AGgl, Hat92, MSs93, Riip93, Riip94, Szy92, Wilgl]). Modules provide a precise interface to the outside world. Inside modules, object identities can be used without restrictions. However, if object identities are used in invariants specifying a system, they may not refer to objects beyond the module's border. Such invariants describe how the classes inside one and the same module relate to each other. In our example, we put the classes Bank, AccountNo, and Account into one module. The following invariant specifies that to each account there is one account number: i n v a r i a n t Vaccountid [ heap[accountid] E Account .
3accountno E AccountNo. (bank[accountno] = accountid) We have achieved a modular specification technique. In fact, we allow for module invariants since each invariant may cover all classes in exactly one module. Since specification is therefore performed for each module, modules can be understood
106
independently of each other. In the presence of object identity, this is very difficult to achieve for single classes. Furthermore, we can locally prove the consistency of a module. Consistency requires that all invariants always hold. The proof obligations for consistency say that all exported methods preserve all invariants or, if a new object is created, establish all invariants. Since invariants do not refer to objects outside the module, such a proof can be done locally, considering only the methods of classes inside the module. Methods that are not exported need not to be taken into account when proving a module's consistency. In our example, it is important that, for instance, a method that introduces a new account also introduces a new account number, with respect to the invariant. Thus, the creation method of Account must not be exported to outside the module, since otherwise the proof obligations could not be fulfilled. Creating new accounts only inside the module, and always along with a new account number, preserves the invariant. The proof obligations being proven, we can guarantee that the invariant of this module cannot be invalidated by any other module. Finally, modules allow for abstraction relationships between components that are less fine-grained than classes. We can describe a module to be compatible with its supermodule, while there may be very different relationships between the classes involved. For the details we refer to [Riip94]. 8
The
Design
Process
To put formal methods into industrial use, it is necessary to integrate them smoothly into a software development life cycle: it is not specification and verification, what software development is all about. We do not even put formal methods in the center of the software life cycle; instead, regarding them to be an efficient means for increasing the quality and safety of software in their most critical parts, we make their use optional and leave the decision whether and where to use them to the developer. A few approaches to integrate formal methods into well-known development models (like SSADM, HOOD, OMT) have been made [PWH91, Lan92]. Our approach differs from these in the choice of the design method and the role formal methods play. As we believe that object-orientation is the most promising technique for the reuse of design, code, and proofs [CLLW93], the latter currently being the most expensive part of the development, we decided to use an object-oriented design method, namely Responsibility Driven Design (RDD) [WBWW90], as a starting point. We decided to use RDD, as we regard it to be the simplest among the numerous objectoriented analysis and design methods [Boo91, RBP+91, WBWW90, Jac92], but also one of the most efficient ones in terms of reusability, flexibility, and comprehensibility of the resulting model. Our experiments with RDD show that RDD lacks of appropriate means to express object behaviour and object interaction. Both aspects are very well supported by the object behaviour diagrams (OBD) and object interaction diagrams, adopted from the approach of Jacobson [Jac92]. Additionally, we find the treatment of inheritance in RDD not adequate (cf. Section 4) and replace this part of RDD. The complete resulting design method is described in [LR95].
107
By introducing object behaviour and object interaction descriptions we succeed in coming closer to a format specification of our classes. So far, the communication architecture of our object system is formally described (via class collaboration graphs and object behaviour descriptions) and can systematically be simulated. It is even possible to prove temporal logic formulas written in terms of objects and states, although so far we did neither formally undergird this nor support this by tools. The last step consists of constructing formal specifications of the method bodies of the classes. This transition can now be done in a very smooth way. We show that with the example of the specification of a simple bank account. A bank account can be overdrawn or can show a positive balance. If it shows a positive balance an amount of money can be withdrawn, but the balance may never be below -10005. This behaviour is depicted by the following OBD:
Yes~ Fig. 1. OBD for the simple account example
Fixing the signature we choose a single integer attribute balance for representing the amount of money currently deposited on the bank, and provide the methods deposit and w i t h d r a w with a single integer parameter a m o u n t . First we describe the states, here ok and overdrawn, with so-called s t a t e invariants:ok = balance > O, o v e r d r a w n = balance < O.
The method bodies can now be specified in a pre-/post-condition like style: deposit is p r e true
p o s t balance' = balance + a m o u n t , w i t h d r a w l s p r e balance >_ 0 A balance - a m o u n t > -1000
p o s t balance' = balance - a m o u n t .
108
A possible class invariant is i n v a r i a n t balance >_ -1000. Now, a number of proof obligations arise, ensuring for instance that - the precondition of a method is at least as strong as the disjunction of the invariants of all states it can be invoked in, - the postcondition of a method is at least as strong as the invariant of the state which follows this method, if the latter is unique, and the class invariant is at least as strong as the disjunction of the state invariants. -
We refer to [LR95] for a complete list of all proof obligations.
Design Patterns. Object-orientation is said to be a strong technique for reuse and extensibility of software designs. Nevertheless, most design methodologies start up from the scratch and do not tackle the situation where some work has already been done and can be reused. The method presented in [LR95] therefore provides for the application of some "reuse mechanisms", the most important being constructed out of the so-called "design patterns", described in [GHVJ93]. We use certain design patterns to construct composed systems out of building blocks, be it classes, families of classes, or modules. We made some experiments in giving design patterns a formal semantics and are thus able to reuse some kind of proof work done for the composed components. Design patterns are in our approach not only useful as a kind of idiom in the language of object-oriented system design, but also as formal construction mechanisms which allow for the smooth integration of different software parts and thus for the reuse of both components and proofs. 9
Summary
and
Outlook
In this article we have outlined how to integrate formal specification and verification into the overall process of object-oriented modelling, design, and programming. The presented specification formalisms lay a foundation of the notion of class refinement which in turn leads towards better design and reorganization of class systems. The proposed proof calculus for object-oriented systems allows to deal with the necessary proof obligations for correct class hierarchies. Modules are introduced as a technical base for the incremental specification and verification of large class systems. With this technique the concept of subsystems can appropriately be supported. Reuse of such subsystems and the related specification and proof work is improved. This basic work on formal object-oriented specification and verification revealed a lot more interesting issues for future work in this field. The presented specifications of classes are mainly done from the viewpoint of single classes. This has to be extended with respect to two aspects: In the development of large systems and frameworks the notion of design patterns has proven to be very useful for providing higher level abstractions. The formal
109
treatment of such cooperating teams of classes has to be supported. Modules seem to be appropriate for describing the encapsulation and parameterization of design patterns. In this context specific module relationships and corresponding proof rules are worked out in more detail. Another aspect is the specification of communication between objects. Global object interaction is formally described with object interaction diagrams, the dynamics of object behaviour is specified using finite state automata. These formalisms shall be semantically integrated into the here presented specification and verification calculus. Up to now some basic work has been done on the treatment of recursive class definitions. The refinement relation for recursive types is not easily defined. As shown in [Web92] the above presented compatibility relation between classes has to be further specialized into conformance and matching (imitation) relationships. Currently, we are working on an extension of the formal foundation for further class relationships, in particular generalization and specialization.
Related work inside the KoRSo project. The work done in the context of Troll light [GCD +, GCH93] is also concerned with object-orientation. The approach taken there is orthogonal to the work reported here with respect to the following two points: - Whereas this paper focusses on the formalization of the notion of inheritance, this technique is not considered in the Troll light work. - Troll light specifications are describing communities of concurrently operating objects, while our calculus cannot deal with concurrency.
Acknowledgements. We are most grateful to Franz Weber, to whom we owe much of our insight in subtyping of recursive types. This work is supported by the German Ministry of Research and Technology (BMFT) under grant number 01 IS 203 M, project "Kol~So".
References [AG91] lAme87]
[Boo91] [BvW89]
[13vW90] [CDD + 90]
A. J. Alencar and A. Goguen. OOZE: An object-oriented Z environment. In P. America, editor, ECOOP 91: European Conference on Object-Oriented Programming, Lecture Notes in Computer Science 512. Springer Verlag, 1991. P. America. Inheritance and subtyping in a parallel object-oriented language. In J. Bezevin, J.-M. Hullot, P. Cointe, and H. Lieberman, editors, ECOOP 87: European Conference on Object-Oriented Programming, Lecture Notes in Computer Science 276. Springer Verlag, 1987. Grady Booch. Object-oriented Design. Benjamin Cummings, 1991. R. J. R. Back and J. yon Wright. Refinement calculus, part i. In REX Workshop for Refinement of Distributed Systems, Lecture Notes in Computer Science 430. Springer Verlag, 1989. R. J. R Back and J. yon Wright. Duality in specification langunges: A latticetheoretical approach. Acta lnformatica, 27, 1990. D.A. Carrington, D. Duke, R. Duke, P. King, G. A. Rose, and G. Smith. Object-Z: An object-oriented extension to Z. In S. Vuong, editor, FORTE 89: Formal Description Techniques. North-Holland, 1990.
110
[CLLW931
[GCD +] [GCH931
[GaVJ93]
[Har92]
[HJSST] [Ja~92]
[Lan92] [L~92]
[LR951
[Mor87] [Mor90] [M6s93] [Nip86] [PWH91]
[RBP+91] [Rap93]
[Rap94] [RWZ931
Eduardo Casals, Claus Lewerentz, Thomas Lindner, and Franz Weber. Formal methods and object-orientation. Technical report, Tutorial at TOOLS Europe 93, Versailles, France, March 1993. M. Gogolla, S. Conrad, G. Denker, R. I-Ierzig, N. Vlachantonis, and H.-D. Ehrich. TROLL light - the language and its development environment. This volume. M. Gogolla, S. Conrad, and R. Herzig. Sketching concepts and computational model of TROLL light. In A. Miola, editor, Proceedings of DISCO '93: Design and Implementation of Symbolic Computation Systems, LNCS. SpringerVerlag, Berlin, Germany, 1993. Erich Gamma, Richard Helm, John Vlissides, and Ralph E. Johnson. Design patterns: Abstraction and reuse of object-oriented design. In O. Nierstrasz, editor, Proceedings ECOOP '93, LNCS 707, pages 406-431. Springer-Verlag, Kalserslautern, Germany, July 1993. Samuel P. Harbison. Modula-3. Prentice Hall, 1992. C. A. R. I-Ioare, He Jifeng, and J. W. Sanders. Prespecification in data refinement. Information Processing Letters, 25 (2), 1987. Ivar Jacobson. Object-oriented Software Engineering: A Use Case Driven Approach. Addison-Wesley, 1992. Kevin Lano. Using formal and structured techniques in object-oriented development. Technical Report BUT-TN-LR 1029, Lloyds Register, 1992. K. Lano and H. Haughton. Reasoning and refinement in object-oriented specification languages. In O. Lehrmann Madsen, editor, ECOOP 92: European Conference on Object-Oriented Programming, Lecture Notes in Computer Science 615. Springer Verlag, 1992. Thomas Lindner and Andreas Rfiping. How formal object-oriented design supports reuse. In Eduardo Casals, editor, Architectures and Processes for Systematic Software Construction, FZI Publication 1/95. Forschungszentrum Informatik, Haid-und-Neu-StralJe 10-14, D-76131 Karlsruhe, 1995. J. M. Morris. A theoretical basis for stepwise refinement and the programming calculus. Science of Computer Programming, 9(3), dec 1987. C. C. Morgan. Programming from Specifications. Prentice Hall, 1990. Hanspeter MSssenb6ck. Object-Oriented Programming in Oberon-2. SpringerVerlag, 1993. T. Nipkow. Nondeterministic data types: Models and implementations. Acta lnyormatica, 11, 1986. F. Polack, M. Whiston, and P. Hitchcock. Structured analysis--a draft method for writing Z specifications. In J. E. Nicholls, editor, Z User Workshop 91, Workshops in Computing, pages 106-122. Spriuger-Verlag, 1991. J. Rumbaugh, M. Blaha, W. Premerlani, F. Eddy, and W. Lorensen. Objectoriented Modeling and Design. Prentice Hall, 1991. Andreas Riiping. Hypertext - a case study of formal object-oriented software development. In Eduardo Casals and Claus Lewerentz, editors, Building Object Oriented Software Libraries, FZI Publication 6/93. Forschungszentrum Informatik, Hald-und-Neu-Strafle 10-14, D-76131 Karlsruhe, 1993. Andreas Riiping. Modules in object-oriented systems. In Raimund Ege, Madhu Singh, and Bertrand Meyer, editors, TOOLS 14: Technology of ObjectOriented Languages and Systems. Prentice Hal/, 1994. Andreas Rfiping, Franz Weber, and Walter Zimmer. Demonstrating coherent design: A data structure catalogue. In Ralmund Ege, Madhu Singh, and
111
Bertrand Meyer, editors, TOOLS 11: Technology of Object- Oriented Languages and Systems. Prentice Hall, 1993. Emil Sekerinski. A calculus for predicative programming. In R.S. Bird, C.C. [Sek93] Morgan, and J.C.P. Woodcock, editors, Mathematics of Program Construction, Lecture Notes in Computer Science 669. Springer Verlag, 1993. Emil Sekerinski. Verfeinerung in der objektorientierten Programmkonstruk[Sek94] tion. PhD thesis, Universit~t Karlsruhe, 1994. Clemens Szyperski. Import is not inheritance - why we need both: Modules [Szy92] and classes. In O. Lehrmann Madsen, editor, ECOOP 92: European Con]erence on Object-Oriented Programming, Lecture Notes in Computer Science 615. Springer Verlag, 1992. M. Utting. An Object-Oriented Refinement Calculus with Modular Reasoning. [Utt92] PhD thesis, University of New South Wales, Kensington, 1992. [WBWWgo] R. Wirfs-Brock, B. Wilkerson, and R. Wiener. Designing Object-oriented Software. Prentice Hall, 1990. [Web92] F. Weber. Getting class correctness and system correctness equivalent - how to get covariance right. In Raimund Ege, editor, TOOLS 8: Technology of Object-Oriented Languages and Systems. Prentice Hall, 1992. [Wil91] Alan Wills. Capsules and types in Fresco: Program verification in smalltalk. Iu P. America, editor, ECOOP 91: European Con/erence on Object-Oriented Programming, Lecture Notes in Computer Science 512. Springer Verlag, 1991.