|
Prev: Teaching OO
Next: multimethod + multiple inheritance
From: Miguel Oliveira e Silva on 3 Mar 2006 11:47 Oliver Wong wrote: > "Miguel Oliveira e Silva" <mos(a)det.ua.pt> wrote in message > news:440751F4.9EF8D419(a)det.ua.pt... > > Oliver Wong wrote: > > > >> > >> If this is true, then DbC is useless in all cases where the > >> contract-designer explicitly wants exceptions thrown under certain > >> conditions. > > > > (I'm not sure to what you are saying.) > > > > DbC simply requires that exceptions be raised everytime > > a runnable assertion fails (nothing more, nothing less). > > > > In DbC the goal is to build programs that behave > > correctly without exceptions. > > What I was saying is that somethings the behaviour of a correct program > is to throw exceptions. If DbC forbids throwing exceptions, then DbC cannot > support programs whose purpose is to throw an exception. Oliver, DbC prescribes a very simple (but not simplistic) view of programming. Modules (classes) should be built with clear and explicit contracts. Contracts express the module correctness assertions. Hence a broken contract is always the manifestation of an incorrect program (we most likely agree to this point). So what DbC imposes is that a false runnable assertion *always* raises an exception (ok?). It does not strictly forbids you from using exceptions for other objectives. No language, even Eiffel, cannot prevent such a thing to happen (although in Eiffel, due to its disciplined exception mechanism, the programmer is forced to do that explicitly on purpose avoiding same nasty program errors). However, a wise programmer, should not use exceptions to deal with situations that can easily be dealt with normal language instructions, or else sooner or later he no longer will know if exceptions are exceptional, or simply another normal control structure (= goto). We can identify two important situations where exceptions are the appropriate tool: (internal) broken contracts, and abnormal behavior due to external unpredictable erroneous situations (not completely controllable by the program). This last case can be thought as been an external broken contract (for example, after testing the existence of a file inside a program one expect the postcondition that the file exists!). In the latter case, a reliable program will need to use the exception mechanism to ensure the correctness of the program (my mistake for not remembering, in previous messages, this rare but, nevertheless, important situation). > [...] > >> But raising the exception might be part of the useful work! For > >> example, > >> let's say you're invoking an old library that uses return-codes to signal > >> error conditions. > > > > Well if you use modules that are not based in DbC, then > > yes all kind of dirt things can happen (as C's "errno" > > and error code as return values). > > > > If possible, wrap them inside appropriate DbC based modules, > > and use them only through those modules (to protect the > > remaining program from undetected propagation of errors). > > Yes, but those "wrapper" modules will not actually be fully-DbC > compliant, under your definition, Not at all. They can be fully DbC compliant (why shouldn't they?). > because of the "dirt" leaking in. But it does not "leak out" (that's the point), so external clients will use a 100% compliant DbC module. > This is why I'm saying there exists a lot of practical situation where DbC as you > define it cannot be used, and a more relaxed-version of DbC is nescessary. I'm not sure you completely understand "my" definition of DbC. DbC is a sufficient methodology to build programs. You are free to put, or remove, conditions from contracts. My advise is that contracts should be reasonable, and assertions should express only correctness program conditions (not exceptional behavior as a result of a program error). If you do want to put exceptional behavior inside contracts (which may not go against DbC), DbC just requires that you don't mix different assertions, and that a false assertions always raises exceptions. Preconditions cannot be expressed as postconditions. > (e.g. one where exceptions are allowed as part of the normal behaviour of > the module). You mean: when an exceptional behavior is a normal behavior? (Why call it exceptional then?) Please don't think I'm playing with words. Exceptions exist for a reason. And that reason is not to replace goto's. > >> > > >> > Should my car accept sand as fuel? > >> > (It would be a weaker precondition.) > >> > >> If it's possible, the engineers should specify the behaviour of the > >> car > >> when sand is used as fuel. > > > > No. The engineers simply put in the contract that > > the car has a precondition of fuel = gasoline (diesel, > > GPL, hydrogen, electricity, or whatever). No need to > > worry about absurd car usages (or else, they would have > > to write an endless and mostly useless contract). > > [...] > > > >> It's better to have accurate information than no information. > > > > Preconditions are accurate information. > > Yes, but the equivalent post-condition gives MORE information. No it doesn't. (See my response to that in the end of this message, when I compare your contracts A and B). > If you > have a pre-condition "A", then the information you have is "If A is false, I > don't know what happens." If it is runnable, an exception is raised (that is not undefined behavior: it is simply an *exceptional* behavior). > If you have a post-condition "if A is false, car > fails", then you now have more information than before, and that's better. Oliver, it is impossible to express all the conditions that should not happen (sand/water/rocks/.../garbage as fuel), so your suggestion is absurd. In contracts, one is bound to express what is required at the start (precondition) and what will arise in the end (postcondition). > That is why I say that if the engineers could have put the "no sand" > pre-condition without any trouble on their part, they should have. Take a little time to think about it. You'll surely see that's absurd. The (runnable) precondition (fuel = gasoline) is more than enough to completely protect the car against other absurd types of fuel. > The problem with the "no sand" precondition There is not a "no sand" precondition (where did you saw such a thing?). The precondition is (fuel = gasoline). > is that if, some day in the > future, they invent a way to allow cars to run on sand, then they cannot > update the underlying implementation of their car to take advantage of this > new feature without changing the interface (and the contract). Of course. In the gasoline car abstraction, sand will never be an acceptable fuel. You can, however, create ADTs for more abstract cars. In fact we can simply use the static type system to solve the fuel problem with generic classes: class CAR[F -> FUEL_TYPE] feature fuel_capacity: DOUBLE; -- maximum amount of fuel possible fuel_level: DOUBLE; -- current amount of fuel fill(amount: DOUBLE) is require amount > 0; fuel_level + amount <= fuel_capacity ensure fuel_level = old fuel_level + amount .... invariant fuel_capacity > 0; fuel_level >= 0 and fuel_level <= fuel_capacity; end -- CAR The class FUEL_TYPE would be an abstract class from which all types of fuels would be required to inherit in order for a CAR to be used. BTW, in Eiffel CAR[F -> FUEL_TYPE] means that CAR is a generic (template) class which only accepts as type parameters types descendant from FUEL_TYPE (hence it is ensured statically that no SAND will ever be used as fuel, unless in the future such a propelling fuel is invented). > But if the engineers are confident that they can guarantee that a car > will ALWAYS fail to run when given sand as fuel, Of course, in my initial analogy, the precondition was (fuel = gasoline). > AND/OR the client > specifically wishes for the behaviour of the car to be it failing when given > fuel, then this behaviour should be specified as a post-condition. (Not again, please!) The condition *precedes* the usage of the car, hence it is a *pre*condition. > [...] > >> > >> The problem with "putting as much preconditions as possible to make > >> implementation easy" is that with that, you can do anything (including > >> the > >> impossible). > > > > That's absurd. Preconditions don't *do* anything. They simply > > assert the client's obligations when using the routine. > > I didn't say the pre-conditions "do" something; I'm saying that with > enough pre-conditions, you (the implementor) are free to do anything. The supplier is only required to do things *iff* preconditions are met. With a false precondition he can do whatever he likes, including nothing. The contract will fail due to the client's responsibility. > > > >> Look, here's a method which solves the halting problem, a > >> problem famous because it is known to be impossible to solve. > >> > >> /* > >> pre-condition: false > >> post-condition: solves halting problem. > >> */ > >> void solveHaltingProblem() { > >> } > > > > Simply because you wrote in the postcondition > > (and in the function name) that the function > > solves the halting problem does not mean that > > it does. > > Yes, but in this case, the function DOES solve the halting problem as > long as the pre-conditions are met. (Who is playing with words now?) A false precondition (as you recognize below) cannot be met. And that fact is not *besides the point*. It is *the* point. (That is why there is a "pre" in preconditions and a "post" in postconditions.) (Perhaps the way you view this problem results from that messy way of viewing contracts, in which you insist in putting broken preconditions as defined behavior in postconditions.) > > > > That function is, by definition, unusable. > > It can't do nothing (you can call "nothing" > > the halting problem, black coffee, a nuclear > > plant; it makes absolutely no difference). > > I'm assuming you mean "It can't do anything" or "it can do nothing". > Well, no, actually, what it does is solves the halting problem precisely > when the pre-conditions are true (which incidentally in this case happens to > be "never", but that's besides the point). (Only in your apparently confused mind.) The supplier knows that the precondition is never met, so he can do anything he wants inside the routine. He also knows that nobody will never try to see if the postcondition is met (so he's off the hook). In case you haven't notice, postconditions are not evaluated alone. They are an implication from preconditions. This basic causal relation is not "besides the point". > Just because something is "unusable" doesn't mean it "does nothing". > Consider this alternate implementation of the same contract: > > /* > pre-condition: false > post-condition: solves halting problem. > */ > void solveHaltingProblem() { > print "Hello world!"; > } Same thing as the other one. > Now if you ignore the documentation and just look at the implementation > (glass-box analysis), even a beginner in programming will tell you that the > function does *something*. *Only* a beginner programmer could say that. Preconditions cannot be ignored by clients. A client will never know if the supplier mets the postcondition. > > > > Any program that attempts to use > > solveHaltingProblem is simply > > incorrect (incorrect is not equal > > to solve the halting problem). > > I'm not claiming that "incorrect" is equivalent to solving the halting > problem. When you put a false precondition in a solveHaltingProblem routine, saying that it solves the problem, then you are indeed saying that incorrect program = solving the halting problem. > Here's a different contract, for example: > > /* > pre-condition: false > post-condition: prints "Hello World" to standard out. > */ > void printHelloWorld() { > print "Goodbye."; > } (Same thing.) > This method also satisfies its part of the contract, The contract is, by definition, broken if any client attempts to use this function. The responsibility for this very unfortunate fact belongs to the client. It is absolutely irrelevant the conditions expressed in *post*conditions. > and the contract says that whenever the pre-conditions are satisfied, it must print "Hello > World" to standard out. The implementation of this function is not > incorrect; By definition, with a false precondition, we will never know if the supplier is incorrect (before that, the client has already be proved guilty). > I claim it is completely free of bugs. Really! A false precondition = free of bugs. (I'm always learning new extraordinary things.) > It does exactly what it is intended to do! Of course: a program error (which is *not* to print "Hello World", then halting problem, or whatever you might like to put *after* a false assertion). > The exact same thing is happening with my "solve halting problem" > function above. Exactly. > It does exactly what it intends to do, which is to solve the > halting problem, given certain assumptions and pre-conditions. (Think again.) > > > >> The more robust each individual method in a system, the more robust that > >> system is as a whole, etc. > > > > Correct. > > > > But robustness is achieved by more preconditions/postcondition/invariants, > > not less. > > No, pre-conditions are assumptions the implementor can make when > implementing the method. Correct. > The fewer assumptions the implementor makes, the > more robust the implementation. Not quite. If we can weaken preconditions and still do useful work (which rules out: raising exceptions), then the routine will be able to serve correctly wider requests from clients (which is good, because it will be a more general routine). However, the problem is that almost always, a routine cannot do useful work out of every request from clients. The robustness problem arises precisely from this problem (to request impossible things to routines). Reliability is ensured when *everyone* mets their part of the contract (not just the clients, but also suppliers). So a reliable program is one in which all assertions are either met (correctness), or, if tested to be false, raises an exception (DbC view of broken contracts). What you don't seem to fully understand is that, no matter what, when one wants to do useful work inside a routine there is almost always a precondition involved, and the problem is not the existence of the precondition, but the limitations we have to put things to work correctly. That was the case of "sqrt", "inverse", the car analogy, and almost any other problem you might think off. For same reason that escapes me (but I keep an opened mind[*]) apparently you seem convinced that because you put in a postcondition an exceptional behavior, there is no precondition involved. The precondition is there, it is simply hidden in the wrong place, with nasty consequences (see the end of the message). [*] but not so open that my brain fall out. (to cite Carl Sagan) > Therefore, the LESS pre-conditions, the more > robust the program. The better contracts are met by everyone the more correct (so also more reliable) the program is (which is not the same as less preconditions). The more you allow false assertions to not raise exceptions, the less robust your program is. > If you have lots of pre-conditions, it's easier to make a change > somewhere in the program which inadvertently violates one of those > pre-conditions, It is not. The contract is part of the public ADT of a module. Once established, the clients know their part of the deal and are also ensured on the module's responsibilities. That is why contracts are required to be inherited by descendant classes (Eiffel does that by default, in other languages it required much more handmade bookkeeping work by the programmer to approach that essential behavior). A contract cannot be changed lightly, neither by clients nor by suppliers (or else correctness problems will arise). > thus rendering the program as a whole incorrect. If you have > ZERO pre-conditions (a noble theoretical goal, but almost impossible to > obtain in practice), then it doesn't matter what changes you make, > elsewhere, you will NEVER break the module which has zero pre-conditions, > because it does not depend on any outside assumptions. > >> Again, look at my halting-problem solver, posted above. This has the > >> best possible pre-condition, and yet it's BAD for the supplier. > > > > Not at all. In fact, it is the dream of a (lazy) supplier > > (whatever he does or does not, the contract is not broken > > due to his responsibility). > > It's bad for the supplier because he cannot get any clients to use it. > What's the point of creating a method if it will never be used? It's wasted > effort on the supplier's part. It was not me who putted as an (absurd) example a routine with a false precondition, so it is not up to me to answer that question. > But I guess it's useless to proceed further with this until we define > metrics for "good" and "bad" for the supplier and client. They are very easy to define. All true assertions are good, and all false assertions are bad. > It is GOOD for the client if he can find an implementation of a contract > which solves his problem without imposing too many pre-conditions. Correct. > It is GOOD for the supplier if he can find a client who will agree to a > contract with the supplier. Correct. > I say the "halting problem" contract is bad for the supplier, because he > will not be able to find any clients who will agree to that contract. That's irrelevant. Since the false assertion is a precondition, that routine is simply bad for clients (that's why they shouldn't use it). > >> > >> Well, to me, the names of things aren't so important as the things > >> themselves, > > > > How can you be sure about things themseves, when > > communicating with someone else, if names have > > fuzzy definitions? > > I've long ago learned that every person has their own "version" of > English, where words mean slightly different things to them. For example, > for some people, the word "clown" carries a connotation of fear, while it > doesn't for others. True. > English isn't as rigorous as one would like, so you will often find > people disagreeing about the meanings or definitions of terms. Agreed. > That's fine. > I don't try to enforce my definitions on other people. When it's not too > much trouble for me, I try to use the same definitions as the person I'm > speaking to, but when I'm concurrently speaking to multiple people, it > occasionally becomes difficult to keep track of what terms mean what to > different people. It's a minor problem, and in practice an insoluble one, so > I just tolerate it. Same with me. > As for "How can you be sure about things themselves", I reply with the > philosophical "How can you be sure of anything?" > > Preconditions are conditions imposed *before* something > > happens, and postconditions *after* that thing has happened. > > If the thing did not happen due to a precondition > > failure, it is absurd to express that as a postcondition. > > If a client wants to know his part of the contract, > > he need only to look at the preconditions. Postcondition > > are the supplier's part of the contract. To hide preconditions > > inside postconditions is asking for trouble. > > There's is no disagreement here. I'm just saying there exist a mapping > from contract A to contract B, where A has one or more pre-condition, and > contract B has fewer pre-conditions, such that any client who accepts A will > be willing to accept B as well. > > E.g.: > > /* > Contract A: > Pre-condition: s is never null. > Post-condition: returns s. > > Contract B: > Pre-condition: none. > Post-condition: if s is null, throws NullPointerException; otherwise, > returns s. > */ > > Any client who accepts contract A here, should also be willing to accept > contract B. From his perspective, they do the same thing. In contract B the precondition should have been the same as in A: (s != NULL). You just made the mistake to hide it inside the postcondition (wrongly making the clients belief that the routine can do useful work regardless of the value of s). Contract B, is much (much) worse than A's because, if s happens to be NULL, the client is not ensured (since the exceptional behavior is in the postcondition) that the routine did not do nothing else besides raising an exception. Hence he may lose the extremely important guarantee that the supplier object invariant is still correct even if the exception was raised (DbC ensures that). That's a very (very) serious problem resulting from putting the (exceptional) behavior of broken preconditions inside postconditions. Another serious problem with B's like contracts happens when the programmer misses an exceptional behavior in postconditions for some runnable (hidden) precondition. The client knows that such a precondition exists, but he will be unsure if the supplier will indeed respond with an exception. Isn't it much simpler to take that for granted as in DbC (without moving assertions to wrong places)? Tell me, why do you put exceptional behavior inside postconditions, and not inside preconditions? (Which would bring your normal *and* exceptional behavior to match DbC.) Afterall, the exception was caused by something that the client did (s=NULL), and not as a result of something inside the supplier's code. (Do we agree in this point?) Again, DbC approach is much simpler and safe: any detected false assertion raises an exception. > - Oliver Best regards, -miguel -- Miguel Oliveira e Silva
From: Oliver Wong on 3 Mar 2006 12:22 <ggroups(a)bigfoot.com> wrote in message news:1141384594.168474.257720(a)z34g2000cwc.googlegroups.com... > Oliver Wong wrote: > > [ Design By Contract saga snipped, but acknowledged ] > >> It's bad for the supplier because he cannot get any clients to use it. >> What's the point of creating a method if it will never be used? It's >> wasted >> effort on the supplier's part. > >> But I guess it's useless to proceed further with this until we define >> metrics for "good" and "bad" for the supplier and client. > >> It is GOOD for the client if he can find an implementation of a contract >> which solves his problem without imposing too many pre-conditions. > >> It is GOOD for the supplier if he can find a client who will agree to a >> contract with the supplier. > > The best components from the users' viewpoint are those that have the > weakest preconditions and strongest post/invariant conditions. > > The suppliers' viewpoint is the converse. > > Within those extremes we have a dynamic where components arrive at > contracts that are amenable to both (usage, implementation effort etc) > . > > Hence the term *contract* . Contracts are negotiated are they not ... The problem with this is that if it were true that it's best for the supplier to implement components with the strongest pre-conditions and the weakest post-conditions, then no one would ever implement any component except for this one: /* pre-condition: false. post-condition: does nothing */ void doesNothing() { } But why isn't that what we observe in real life? Because there's an ADDED factor that a supplier will not want to waste his/her time implementing a component that no one wants to use! That's the point I was trying to make. - Oliver
From: Dmitry A. Kazakov on 3 Mar 2006 13:07 On 3 Mar 2006 03:16:34 -0800, ggroups(a)bigfoot.com wrote: > Oliver Wong wrote: > > [ Design By Contract saga snipped, but acknowledged ] > >> It's bad for the supplier because he cannot get any clients to use it. >> What's the point of creating a method if it will never be used? It's wasted >> effort on the supplier's part. > >> But I guess it's useless to proceed further with this until we define >> metrics for "good" and "bad" for the supplier and client. > >> It is GOOD for the client if he can find an implementation of a contract >> which solves his problem without imposing too many pre-conditions. > >> It is GOOD for the supplier if he can find a client who will agree to a >> contract with the supplier. > > The best components from the users' viewpoint are those that have the > weakest preconditions and strongest post/invariant conditions. > > The suppliers' viewpoint is the converse. > > Within those extremes we have a dynamic where components arrive at > contracts that are amenable to both (usage, implementation effort etc) > > Hence the term *contract* . Contracts are negotiated are they not ... Maybe, but there is also somebody who assigns suppliers and consumers, responsible for the problem decomposition. Now the question is, when the negotiation takes place. Before or after the roles have been identified? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: Miguel Oliveira e Silva on 3 Mar 2006 13:13 "Dmitry A. Kazakov" wrote: > On Thu, 02 Mar 2006 15:43:30 +0000, Miguel Oliveira e Silva wrote: > > > That's where he is wrong. You see, in your workaround runnable assertion > > the precondition is correctly putted *before* the routine starts the execution > > of its hopefully useful algorithm. If I call "foo" in (C++/Java) without a > > try/catch block the exception will pass by me (without I'm being aware of it). > > Hence: > > > > // somewhere in a program > > do_x; > > r = foo(s); > > do_y(r); > > > > before "do_y" the assertion that this code ensures is the postcondition > > of "foo", which -in order for the program not to be incorrect- should > > ensure do_y's precondition. > Not quite. r = foo(s) ensures a conjuction of preconditions. You assume that exceptions raised due to false preconditions, disguised as a postcondition, are part of a correct program. I do not (is this reasonable to you?). > One part is > the precondition of do_y, another is a conjuction of the preconditions of > all enclosing catch-blocks. > > Consider: > > try > { > do_x; > r = foo(s); > post: r /= null V NullStringException = P1 > pre: r /= null = P2 > do_y(r); > post ... > } > post: ... V NullStringException > catch (NullStringException) > pre: NullStringException = P3 > { > ... > } > > P1 => P2 V P3. It's fine. Correct. My point, is that P3 is not part of "do_y"'s precondition (an exception is never a precondition of normal routines/instructions, only for catch/rescue blocks). So I was using a "reductio ad absurdum" argument, in which I attempted to show that exceptional behavior (being goto like) is outside normal structured (single entry and exit points) view of programs. So, exceptions are required to take into consideration code outside normal program structured instructions (as you did, by including a possible catch block). Using them for normal program behavior is not a structured approach, hence it makes it much harder to reason on program correctness. > -- > Regards, > Dmitry A. Kazakov > http://www.dmitry-kazakov.de Best regards, -miguel -- Miguel Oliveira e Silva
From: Oliver Wong on 3 Mar 2006 13:32
"Miguel Oliveira e Silva" <mos(a)det.ua.pt> wrote in message news:44087328.68DFA1A7(a)det.ua.pt... > Oliver Wong wrote: [snipped everything except Contract-A and contract-B, which seems to be the core issue now] >> There's is no disagreement here. I'm just saying there exist a >> mapping >> from contract A to contract B, where A has one or more pre-condition, and >> contract B has fewer pre-conditions, such that any client who accepts A >> will >> be willing to accept B as well. >> >> E.g.: >> >> /* >> Contract A: >> Pre-condition: s is never null. >> Post-condition: returns s. >> >> Contract B: >> Pre-condition: none. >> Post-condition: if s is null, throws NullPointerException; otherwise, >> returns s. >> */ >> >> Any client who accepts contract A here, should also be willing to >> accept >> contract B. From his perspective, they do the same thing. > > In contract B the precondition should have been the same > as in A: (s != NULL). > You just made the mistake to hide it inside the postcondition > (wrongly making the clients belief that the routine can do > useful work regardless of the value of s). Whether something is "useful" or not depends on the client's opinion. Perhaps the client specifically wants a NullPointerException (and not , e.g., AssertionException) to be thrown when s is equal to null, and therefore B is MORE useful than A. A does not specify what will happen if s is null. If the client is writing code which critically depends on NullPointerException being thrown when s is null, then the client MUST use B, and CANNOT use A. If the client will never set s = null, the nthe client can use either B or A, as they will both perform identically for all situations the client will encounter. That is why I say any client who accepts contract A will also accept contract B. > > Contract B, is much (much) worse than A's because, > if s happens to be NULL, the client is not ensured (since > the exceptional behavior is in the postcondition) that > the routine did not do nothing else besides raising an > exception. Hence he may lose the extremely important > guarantee that the supplier object invariant is still correct > even if the exception was raised (DbC ensures that). > That's a very (very) serious problem resulting > from putting the (exceptional) behavior of broken > preconditions inside postconditions. This is a problem with all contracts: post conditions generally don't list all the things they DON'T do. E.g.: /* Pre-condition: None. Post-condition: Returns true. Does not emit anything to standard out. Does not allocate RAM. Does not kill children. Does not cause your car to explode. Etc. */ bool getTrue() { return true; } Usually, if a contract does not mention behaviour Foo, it can safely be assumed that the method will NOT do contract Foo. If this is a problem for the client, the client should negotiate a new contract where the desired behaviour is made explicit. Contract B says that the method will return s except when s is null, in which case it will throw NullPointerException. Note that the post-condition does not say things like "BTW, I am free to violate any class constraints, etc." And because it doesn't say that, it won't do that. Exceptions do not indicate that class invariants might have been violated. This fear is unjustified. > > Another serious problem with B's like contracts > happens when the programmer misses an > exceptional behavior in postconditions for > some runnable (hidden) precondition. > The client knows that such a precondition > exists, but he will be unsure if the supplier > will indeed respond with an exception. > Isn't it much simpler to take that for > granted as in DbC (without moving > assertions to wrong places)? There is NO pre-condition in contract B. Not even a hidden one. I don't know why you say there is. If the client "knows" that such a pre-condition exists, then that client has obviously misunderstood the contract. There is not pre-condition. If the client carefully reads the contract, he will see that the behaviour of the method is to return s when s is not null, and to throw NullPointerException when s is null. The client therefore knows the behaviour of the method in the cases where s = "Dog", s = "Hello World!", s = null, and an just about every other situation that will arise. The behaviour is explicitly stated in the contract. > > Tell me, why do you put exceptional behavior > inside postconditions, and not inside preconditions? > (Which would bring your normal *and* exceptional > behavior to match DbC.) Contract A and contract B describe two different behaviours. If I want the behaviour of contract B, I must use contract B. I cannot use contract A, because it (might) do something different than contract B. The original claim up thread is that all contracts with runnable pre-conditions that are accepted by a given client can be converted into another contract with fewer (possibly zero) pre-conditions which will also be accepted by a client. The reverse is not nescessarily true. > > Afterall, the exception was caused by something > that the client did (s=NULL), and not as a result > of something inside the supplier's code. (Do we > agree in this point?) No, I'm not sure that we are in agreement. When you talk about "cause", it can get philosophical too: A: "Why was this exception thrown?" B: "Because there's a throw clause in the supplier's code." A: "Why is there a throw clause in the supplier's code?" B: "So that the code satisfies the contract given." A: "Why is the contract written the way it is written?" B: "Because that's what the client and the supplier agreed upon." etc. > > Again, DbC approach is much simpler and safe: > any detected false assertion raises an exception. This sentence does not nescessarily imply that ALL raised exceptions are caused by a detected false assertion. - Oliver |