To: patterns@cs.uiuc.edu Subject: Patterns (third in a series): Checking vs. Trusting Collaborators Reply-To: Don Dwiggins Date: Tue, 6 Dec 94 10:46:59 PST From: dwig@markv.com Checking vs. Trusting Collaborators Intent ------ Provide a principled approach to deciding where run-time checking should be applied. Motivation ---------- A classic problem that has plagued software developers since the early days is, when to check inputs (and returns from calls), and what to do if an error is detected? An extreme approach to design is to have every module, no matter how deeply embedded, check every input for validity on each invocation. An opposite extreme is to trust the validity of all inputs, even from outside the system. Run-time checking increases the size of the system and slows it down, as well as presenting design problems: if a module deep in the system detects an invalid input, what should it do? In addition, the checking complicates the logic of the module, making it harder to follow and modify. Applicability ------------- When considering the range of unexpected or invalid inputs/events to a subsystem. Solution -------- At least some modules should trust their collaborators to provide valid inputs; this should be resolved during design when laying out the communication across boundary of a subsystem, along with the issue of how to handle exceptions. {Needs considerable elaboration, subpatterns to identify when and how to check, when to trust.} Use assertions to document and test assumptions, explicit checking code and exception raising where assumptions can't be made. Consequences ------------ {TBD} Implementation -------------- {TBD} Related patterns ---------------- CHECKS pattern language. Examples of use --------------- {TBD} Don Dwiggins "Solvitur Ambulando" Mark V Systems, Inc. dwig@markv.com Date: Wed, 7 Dec 1994 07:56:53 -0600 To: patterns@cs.uiuc.edu From: johnson@cs.uiuc.edu (Ralph E. Johnson) Subject: Checking vs. Trusting Collaborators Here are my thoughts on when to check and when to trust. Public functions should check, private functions should trust. But sometimes public functions do all their work by calling other public functions; they should trust, too, and let their callees do the checking. Life gets complicated in OO systems. Sometimes a method is public to a class but private to the subsystem it is in. In other words, the method is called only by other code in the subsystem, though not in the class. In that case, the method should trust. In other words, functions should check only if they are going to be called by functions written by someone who didn't write the function being called. That is the definition of public that should be used here, not the C++ definition. -Ralph Johnson To: johnson@cs.uiuc.edu Cc: patterns@cs.uiuc.edu Subject: Re: Checking vs. Trusting Collaborators Reply-To: Don Dwiggins Date: Wed, 7 Dec 94 10:21:00 PST From: dwig@markv.com Source-Info: From (or Sender) name not authenticated. Ralph Johnson writes: > Life gets complicated in OO systems. Sometimes a method is > public to a class but private to the subsystem it is in. In > other words, the method is called only by other code in the > subsystem, though not in the class. In that case, the method > should trust. In other words, functions should check only if > they are going to be called by functions written by someone who > didn't write the function being called. That is the definition > of public that should be used here, not the C++ definition. > -Ralph Johnson I believe the checking vs. trusting decision should be made during the design process, possibly well before it's known who's going to write the functions that are currently being specified. As I mentioned, when the system and subsystem boundaries are being laid out, and the communication across each of those boundaries is being defined, that's when the trust/check decisions should be made (or at least identified explicitly as an issue to be resolved -- lazy design processing). OK, should a framework or library designed for reuse be trusting or checking? It depends, and I can conceive of an individual method at the API trusting some inputs and checking others. In any case, the documentation should make it clear, e.g., "This parameter must have one of the following values: ... It is not checked, and strange errors may occur if its value is wrong". Don Dwiggins It's important to have a plan -- Mark V Systems, Inc. it gives you something to deviate from dwig@markv.com Date: Wed, 7 Dec 94 12:17:07 CST From: mithani@mojo.i2.com Message-Id: <9412071817.AA14518@mojo.intellection.com> To: patterns@cs.uiuc.edu Cc: johnson@cs.uiuc.edu Subject: Re: Checking vs. Trusting Collaborators > Date: Wed, 7 Dec 1994 07:56:53 -0600 > From: johnson@cs.uiuc.edu (Ralph E. Johnson) > > Life gets complicated in OO systems. Sometimes a method is > public to a class but private to the subsystem it is in. In > other words, the method is called only by other code in the > subsystem, though not in the class. In that case, the method > should trust. In other words, functions should check only if > they are going to be called by functions written by someone who > didn't write the function being called. That is the definition > of public that should be used here, not the C++ definition. > This is not very simple to determine if we consider reusability. Consider a sub-system of classes A, B and C, where functions of B and C are only called by A. Following the above rule, methods of B must be trusting. At a latter time, like all good classes, B ends up being reused in another sub-system; this will be kosher only if the classes in this new sub-system understand that B is a trusting class. In other words, what I am trying to point out is that some methods of the class are by themsleves trusting and others are checking. Of course, it could simply certain designs if the entire class was made either trusting or checking, as otherwise each method must be documented as to whether it is trusting or checking. Sorry, I am new the Patterns stuff, and all of the above may be obvious to the wizards. -- Rizwan Mithani Member of Technical Staff I2 Technologies, Dallas, TX (Rizwan_Mithani@i2.COM) To: patterns@cs.uiuc.edu Subject: Re: Patterns (third in a series): Checking vs. Trusting Collaborators Date: Wed, 07 Dec 94 19:06:14 +0100 From: Dirk Riehle Status: O > Solution > -------- > At least some modules should trust their collaborators to provide valid > inputs; this should be resolved during design when laying out the > communication across boundary of a subsystem, along with the issue of how to > handle exceptions. > > {Needs considerable elaboration, subpatterns to identify when and how to > check, when to trust.} > > Use assertions to document and test assumptions, explicit checking code and > exception raising where assumptions can't be made. Such an elaboration which I really liked has been carried out by Bertrand Meyer under the label "Design By Contract". I'm afraid it hasn't been done using our beloved pattern form but nevertheless I enjoyed reading it. Mey91 Bertrand Meyer. "Design by Contract". Advances in Object-Oriented Software Engineering. Edited by Dino Mandrioli und Bertrand Meyer. London ??: Prentice-Hall, 1991. 1-50. K Dirk Date: 07 Dec 94 11:08:30 EST From: Kent Beck <70761.1216@compuserve.com> To: "INTERNET:dwig@markv.com" Cc: Patterns Subject: Patterns (third in a series): Checking vs. Trusting Collaborators One of the primary forces in this pattern is clarity of expression. Code that is littered with checks is harder to read. When you have typical Smalltalk methods, you might have four or five lines of checks and two lines of executable code. The sense of the code gets lots in all the noise. Some people would say that the checks help communicate what is expected as inputs to a method. I don't find them that much more helpful than the usual Smalltalk conventions. The best answer is to have the system generate contracts for you, check them in the background, and show them on demand. Kent Date: Wed, 7 Dec 94 16:33:26 PST From: Patrick D Logan To: patterns@cs.uiuc.edu Subject: Re: Checking vs. Trusting Collaborators > johnson@cs.uiuc.edu (Ralph E. Johnson) writes: > > Life gets complicated in OO systems. > ...the method is called only by other code in the > subsystem... In that case, the method should trust. > In other words, functions should check only if > they are going to be called by functions written by someone [else] > Rizwan_Mithani@i2.COM writes: > > This is not very simple to determine if we consider reusability. > ...In other words, what I am trying to point out is that some > methods of the class are by themsleves trusting and others > are checking. There are opposing forces. On the one hand, you don't want to check because of the cost of checking. On the other hand, you want to check to ensure safety or at least provide graceful abortion. My pattern has been to push the responsibility "upward" to the client (and document this as part of the "contract", as mentioned here earlier.) I am not sure why yet. As I write this, my first explanation is that otherwise the code become bogged down in redundant checks. In "debug mode" I usually have code around to do copious checking, especially when calling from Smalltalk to C, for example. In "delivery mode" that code is replaced with the faster code, knowing that if I have to debug I place the other back in. If I am lucky, the problem is still reproducable. Once in a while it is not. (But then it is usually a stupid low-memory problem on Windows, but I dgress.) Note that this is not much different from my understanding of the way Eiffel programmers do their "contract" development. I.e. assertions typically get turned off on delivery due to performance issues. === Patrick_D_Logan@ccm.jf.intel.com Intel ProShare Teleconferencing (503) 264-9309 FAX: (503) 263-3375 "What I envision may be impossible, but it isn't impractical." -Wendell Berry To: patterns@cs.uiuc.edu Subject: Re: Patterns (third in a series): Checking vs. Trusting Collaborators Date: Thu, 08 Dec 94 15:23:43 +0100 From: Dirk Riehle Kent wrote: > Some people would say that the checks help communicate what is expected as > inputs to a method. I don't find them that much more helpful than the usual > Smalltalk conventions. The best answer is to have the system generate > contracts for you, check them in the background, and show them on demand. I think so too. One efficient way is to think of client objects delegating work to server objects that offer a contract to fulfill the delegated tasks. The contract may be specified in elaborated forms (see e.g. the Helm et al. 1989 OOPSLA paper) or by using a simple pre & postcondidition schema for each operation (Meyer, Design by Contract). Using pre&postconditions, the preconditions describe the obligations the client object has to fulfill before using a specific service, i.e. an operation or a bundle of operations of the server object. Thus, this has to be checked and ensured by the client. To ensure the contract is fulfilled properly, the server object has to check whether the postconditions are met after executing that operation. So client objects check preconditions and server objects check postconditions, thus, both ensure that the contract is fulfilled. Doing this, the client doesn't have to check the outcome of an operation with respect to what is guaranteed in the postconditions of the contract avoiding tons of duplicated and redundant code. This can be supported by a programming language very well. Eiffel e.g. uses pre&postconditions to make the contract explicit. Both Eiffel and C++ provide an exception handling mechanism that should be used when the contract is violated. An exception is always thrown by the server object, if the preconditions or the postconditions aren't met. Dirk