|
Prev: Teaching OO
Next: multimethod + multiple inheritance
From: Miguel Oliveira e Silva on 1 Mar 2006 10:32 "Daniel T." wrote: > (...) > > > If a precondition is not met, the behavior of the code cannot even be > > > considered... > > > > Agreed. The program is incorrect (the error is somewhere within > > the caller's code). > > Funny, you agree that "if a precondition is not met, the behavior of the > code cannot even be considered", When a precondition fails, it is useless to think about the normal behavior of programs (that was what I though you were referring to). As I said too many times, the program is incorrect, hence it should not run, or else appropriate exceptional behavior is desirable and even required if the faulty precondition was detected at runtime. (You seem to be concerned about a pure theoretical concept of preconditions with little practical use when our static verification tools are unable to prove their correctness. I am concerned about how we can approximate them in practical programming to help us build more reliable programs.) > yet you spend a lot of bandwidth > considering what the behavior of the code should be when a precondition > is not met... (... normal versus exceptional ...) Another thing that puzzles me, is why do you keep arguing that runnable preconditions are not preconditions just because they do what is required to be done when an incorrect program is detected? They are not (obviously) proved preconditions. Nevertheless they are a practical approximation of the desirable behavior, and sometimes they even express the expected formal condition (equal to its pure mathematical counterpart). Of course they cannot prove program correctness at runtime, they can, nevertheless, correctly detect some incorrect programs (which is a huge contribution to approximate correctness and to produce quality reliable software). Also you seem to consider, for some reason, that exceptions are part of normal program behavior (reason why you insist in not fully understanding what I'm saying). That, in my opinion (and in DbC's), is a basic misunderstanding of this mechanism. Its existence is exactly to allow us to think and use two separated worlds: normal program behavior and exceptional behavior. In the former our primary objective is to reach correctness. The latter aims at robustness, either for a faster detection of errors and their correction, or for implementing fault tolerant techniques. > (...) > Eiffel's pseudo-preconditions that really aren't because they have > defined behavior. A precondition is a condition expected to be observed before the routine starts its execution. Eiffel require clauses *are* preconditions (such as ensure clauses are postconditions and invariant clauses are invariants). > Please understand, I'm not deriding Eiffel here, I > think it is good to limit preconditions precisely because we can't > reason about the behavior of programs when they are not met (and we need > to be able to reason about the behavior of our programs.) > > > > Here, I've been talking about real preconditions, ones that > > > require being met or we cannot determine the outcome. > > > > All preconditions (postconditions, invariants and other assertions) > > are required to be met in correct programs. So I think I've been > > talking about the same things. > > > > DbC prescribes a very simple and precise behavior. > > If you have alternative practical proposals -based on > > the mathematical foundations in which most likely > > we all agree- I'm all ears. > > And therein lies the rub. "the behavior cannot even be considered" (you > know, that part you agreed to above?) means there is no solution, nor > can we even consider one. > > As such we must do our best to remove preconditions in our code and > provide well defined results for anything detectable. No. > Eiffel does this by creating a postcondition, No it doesn't. > "if a parameter is a certain value an > exception will be raised." That is not part of the postcondition (how could it be if the routine did not start its execution!). It is the exceptional behavior as a result of a failed precondition. > I'm fine with that, it's a great idea, but it > isn't a precondition Of course it is. It was a condition expected to be verified by the client *before* (as in *pre*) the routine starts its execution. In this respect, it is irrelevant if the error was found statically or at runtime. (References please.) > (which is a good thing, because preconditions are bad.) ? Preconditions, postconditions, invariants and other assertions are good. They make it quite clear what are the contracts expected, and they give us an idea of the meaning of programs (reusing Floyd's article title). > -- > Magic depends on tradition and belief. It does not welcome observation, > nor does it profit by experiment. On the other hand, science is based > on experience; it is open to correction by observation and experiment. Best regards, -miguel -- Miguel Oliveira e Silva
From: Dmitry A. Kazakov on 1 Mar 2006 11:15 On Wed, 01 Mar 2006 15:04:41 GMT, Oliver Wong wrote: > I didn't bring this up earlier, 'cause it didn't seem like an important > point, but since this example is being quoted, paraphrased, repeated, etc. > all over this thread, I figure I should say it now. > > I think 1/0 is defined by IEEE to be equal to positive infinity, not > NaN. You are right. Positive / 0 = +Infinity Negative / 0 = -Infinity 0/0 = NaN. NaN is would be OK (in fact for any operation. I think it is called Quiet NaN, QNaN), but +Infinity is much better. > (negative) infinity divided by (negative) infinity is equal to NaN. > Maybe infinity minus infinity is also NaN, Yes. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: Oliver Wong on 1 Mar 2006 15:03 "Miguel Oliveira e Silva" <mos(a)det.ua.pt> wrote in message news:4405BE7C.41AD05C9(a)det.ua.pt... > > When a precondition fails, it is useless to think about the normal > behavior of programs (that was what I though you were referring to). > As I said too many times, the program is incorrect, hence it should > not run, or else appropriate exceptional behavior is desirable and > even required if the faulty precondition was detected at runtime. I think if a precondition fails, it is useless to think about the behaviour of a program, period. Not merely the "normal" behaviour, but ALL behaviour is unpredictable. Perhaps an incorrect program should not run, but once it's running, it's too late! The program is controlling its own control-flow, and there isn't anything you can really do, unless the OS itself can detect incorrectness and shut down the process associated with the program (but detecting incorrectness is theoretically impossible anyway). [...] > >> yet you spend a lot of bandwidth >> considering what the behavior of the code should be when a precondition >> is not met... > > (... normal versus exceptional ...) The problem is the conflating of two concepts of "exceptional" here. There's exceptional situations which are correctly handled (e.g. by using catch blocks) and can be part of the well defined behaviour of a correctly implemented program. Then there's the "super-exceptional" situations which indicate that there is a bug in the program. /* Pre-conditions: filename should refer to a valid file. Post-conditions: Returns a handle to the specified file, or throws FileNotFoundException if the file does not exist. */ void File openFile(String filename) { //Implementation goes here } If the file doesn't exist, by contract, the method MUST throw an FileNotFoundException. It is NOT a pre-condition that the file must exist. The file may or may not exist; the behaviour of the method is defined in both cases. However, if the filename does not refer to a legal file name; for example if it is equal to "!!*$*!(*", then the behaviour is NOT specified by the contract. Any behaviour is possible. An exception *MIGHT* be thrown, or null might be returned, or any of several other possibilities. > > Another thing that puzzles me, is why do you keep arguing that > runnable preconditions are not preconditions just because > they do what is required to be done when an incorrect program > is detected? I believe Daniel is taking the position that if "preconditions" are runnable, then they are part of the well defined behaviour of the program, and thus are part of the post-condition contract. It's not something I agree with though. (IMHO,) whether something is a pre-condition or not depends on the person writing the contract, and NOT on the implementation of the method that is supposedly fufilling that contract. For example, consider the following two methods: /* pre-condition: s is not null. post-condition: returns s. */ String foo(String s) { return s; } /* pre-condition: none. post-condition: returns s. */ String foo(String s) { return s; } Both of these methods satisfy their contracts. But notice that the implementation for both methods is exactly the same. And yet, one of the contracts has a pre-condition, and the other one doesn't. Therefore, I don't think one should determine what the pre-conditions of a method are based on the implementation of that method. Therefore, with a program like this: /* pre-condition: s is not null. post-condition: returns s. */ String foo(String s) { assert s != null; return s; } "s != null" is a runnable pre-condition. But it's also a "real" pre-condition, in the sense that yes, this contract really does have a pre-condition. The contract didn't have to be designed this way; but that's the way it was designed. The fact that the pre-condition is runnable does not make it any less real. However, note that the following method also satisfies its contract: /* pre-condition: none. post-condition: returns s if it is not null, otherwise throws an AssertionException. */ String foo(String s) { assert s != null; return s; } So Daniel, I think, is saying that runnable pre-conditions can always be converted to post-conditions. That part I agree with. But I don't agree with the idea that this nescessarily means runnable pre-conditions are less real. > > Also you seem to consider, for some reason, that exceptions are > part of normal program behavior (reason why you insist in not > fully understanding what I'm saying). That, in my opinion (and in > DbC's), is a basic misunderstanding of this mechanism. > Its existence is exactly to allow us to think and use two > separated worlds: normal program behavior and exceptional > behavior. In the former our primary objective is to reach > correctness. The latter aims at robustness, either for a > faster detection of errors and their correction, or for > implementing fault tolerant techniques. See above. There's 3 worlds. Handling routine normal situations, handling exceptional situations, and being incorrectly implemented. Violating the pre-condition puts you in the "incorrectl implemented" world, not the "handling exceptional situation" world. > >> (...) > >> Eiffel's pseudo-preconditions that really aren't because they have >> defined behavior. > > A precondition is a condition expected to be observed > before the routine starts its execution. Eiffel require clauses > *are* preconditions (such as ensure clauses are postconditions > and invariant clauses are invariants). I think Daniel is saying that Eiffel require clauses are implementation detail which allows the programmer to cause the program to behave in certain ways. They can be used to check pre-conditions, or they can be used to enforce post-conditions. They are not THEMSELVES pre-conditions; they are tools for checking pre-conditions. > >> Please understand, I'm not deriding Eiffel here, I >> think it is good to limit preconditions precisely because we can't >> reason about the behavior of programs when they are not met (and we need >> to be able to reason about the behavior of our programs.) >> >> > > Here, I've been talking about real preconditions, ones that >> > > require being met or we cannot determine the outcome. >> > >> > All preconditions (postconditions, invariants and other assertions) >> > are required to be met in correct programs. So I think I've been >> > talking about the same things. >> > >> > DbC prescribes a very simple and precise behavior. >> > If you have alternative practical proposals -based on >> > the mathematical foundations in which most likely >> > we all agree- I'm all ears. >> >> And therein lies the rub. "the behavior cannot even be considered" (you >> know, that part you agreed to above?) means there is no solution, nor >> can we even consider one. >> >> As such we must do our best to remove preconditions in our code and >> provide well defined results for anything detectable. > > No. Yes. The fewer pre-conditions your methods have, the fewer situations in which the method will behave in an undefined manner, and thus the more robust that method is. > >> Eiffel does this by creating a postcondition, > > No it doesn't. I won't get into this, since I think it's just a matter of choice of words. You're both right. > >> "if a parameter is a certain value an >> exception will be raised." > > That is not part of the postcondition (how could it > be if the routine did not start its execution!). > It is the exceptional behavior as a result of a failed > precondition. > >> I'm fine with that, it's a great idea, but it >> isn't a precondition > > Of course it is. It was a condition expected > to be verified by the client *before* (as in *pre*) > the routine starts its execution. In this respect, > it is irrelevant if the error was found statically > or at runtime. > > (References please.) > >> (which is a good thing, because preconditions are bad.) > > ? > > Preconditions, postconditions, invariants and other > assertions are good. They make it quite clear > what are the contracts expected, and they give > us an idea of the meaning of programs (reusing > Floyd's article title). Preconditions are bad, but specifying pre-conditions are good. <analogy> If I break my girlfriend's expensive vase, that's bad. If I admit to her that I did it, and apolozie, that's good. </analogy> We should have as few preconditions as reasonably possible (we should break as few vases as possible), but any pre-conditions we are unable to eliminate, we should should clearly specify (we should admit whenever we break a vase instead of lying about it). - Oliver
From: Bjorn Reese on 1 Mar 2006 16:54 Daniel T. wrote: >>>// returns NaN if x == 0 >>>double inverse( double x ) { >>> return 1/x; >>>} Returns positive infinity, not NaN. > We'd have to define that as well I guess. "ensure inverse(NaN) == 0" Returns NaN, not 0. The above assumes IEEE 754. -- mail1dotstofanetdotdk
From: Miguel Oliveira e Silva on 2 Mar 2006 10:43
Oliver Wong wrote: > "Miguel Oliveira e Silva" <mos(a)det.ua.pt> wrote in message > news:4405BE7C.41AD05C9(a)det.ua.pt... > > > > When a precondition fails, it is useless to think about the normal > > behavior of programs (that was what I though you were referring to). > > As I said too many times, the program is incorrect, hence it should > > not run, or else appropriate exceptional behavior is desirable and > > even required if the faulty precondition was detected at runtime. > > I think if a precondition fails, it is useless to think about the > behaviour of a program, period. Not merely the "normal" behaviour, but ALL > behaviour is unpredictable. Yes and no ;). Precisely one of the positive side-effects of runnable preconditions (and other assertions) is to prevent programs to "shoot themselves in the foot" (by stopping at that point normal program execution, giving the possibility for fault tolerant alternative execution paths). (Preconditions, can not only exist in executable programs, but they are also part of the good guys.) In theory, unless we are able to prove statically the correctness of programs, the behavior of *any* program is unpredictable. After all we can't be entirely sure that there could be a false untested assertion somewhere in the program. In practice, our best defense within a program, is to ensure -with every means possible- that all assertion are correct, and immediately take preventive measures when the first one fails. We won't be sure that the program state will be completely stable (we almost never are), but we are guaranteed that the runnable invariants of all objects -except probably the one responsible for the failure (in the case of preconditions that would be the caller)- are observed (a very important property deal with failures). > Perhaps an incorrect program should not run, but once it's running, it's > too late! Yes and no. Afterall if a got a flu, the problem was not the fact that I'm alive! Surely to shoot me down would be a solution for it, but not quite a solution for me. Nevertheless the best solution if programming would be -if possible- to terminate the program, correct the error, and try again. > The program is controlling its own control-flow, Yes. But in DbC we take a rather extreme view of program control flow: there is the normal program flow (desirable OO and structured); and there are exceptions as a safety belt if anything detectable goes wrong. This non-negotiable separation, helps us to think clearly about program correctness, and provides a powerful methodology for preventing programs to hurt themselves, hence increasing their possibilities to recover from faulty situations. > and there isn't > anything you can really do, unless the OS itself can detect incorrectness > and shut down the process associated with the program (but detecting > incorrectness is theoretically impossible anyway). > > [...] > > > >> yet you spend a lot of bandwidth > >> considering what the behavior of the code should be when a precondition > >> is not met... > > > > (... normal versus exceptional ...) > > The problem is the conflating of two concepts of "exceptional" here. > There's exceptional situations which are correctly handled (e.g. by using > catch blocks) (Fault tolerance as a result of a detected failure of a runtime assertion.) > and can be part of the well defined behaviour of a correctly > implemented program. I understand your point, but that is not DbC approach. In there, a correctly implemented program never raises exceptions. On the other hand a fault tolerant program, by providing redundant execution paths, may be shielded against some incorrect sub-programs inside itself, and -at the end- might also behave correctly (as you are arguing). > Then there's the "super-exceptional" situations which > indicate that there is a bug in the program. > > /* > Pre-conditions: filename should refer to a valid file. > Post-conditions: Returns a handle to the specified file, or throws > FileNotFoundException if the file does not exist. Don't put a failure of a precondition in the postcondition. If the (runnable) precondition fails the function won't be executed. I know that in languages with the try/catch construct, you are used to think of exceptions as a result of the execution of a block, but that is not entirely correct. After all if an exception happens inside a function it will only be cached in the first nested try/catch block, not necessarily in the direct caller of the function. > */ > void File openFile(String filename) { > //Implementation goes here > } > > If the file doesn't exist, by contract, the method MUST throw an > FileNotFoundException. Yes, if it is in the contract (and it should), an exception must be raised. But not as a result of a postcondition (the failure was in the precondition). This is not a mere detail (so please excuse my stubbornness). A precondition failure, points the accusing finger towards the caller. There is no need to express that fact in a postcondition. The postcondition should only be concern with the correctness (within the normal execution world, and not in the exceptional world) assertions applicable to the implementation of the routine. This DbC approach simplifies things tremendously. The exception should be raised not because the postcondition says so, but simply because there was a failure in the precondition. I have also a pragmatic critique to that approach. How do you impose, at runtime, that "postcondition" part of the contract to a method (and to all its possible redefinitions in descendant classes)? Why put something as a comment (//throw exception) when it can (and should) be part of normal runnable assertion semantics? What if you forgot to express exceptions in the postconditions in method with (runnable) preconditions? Does that mean that not raising an exception would be a valid "behavior" of the module when the precondition fails? In programming (as in life) there are many things we take from granted (an exception is the response to a false assertion). No need, and no gain, to express them everywhere. > It is NOT a pre-condition that the file must exist. > The file may or may not exist; the behaviour of the method is defined in > both cases. > > However, if the filename does not refer to a legal file name; for > example if it is equal to "!!*$*!(*", then the behaviour is NOT specified by > the contract. The normal behavior isn't (by definition). But if the method has the runnable precondition: file_exists(filename), then an exception will be raised and no harm was done to the object's state (the routine was not executed). > Any behaviour is possible. "Any behavior" is not acceptable. (DbC does not allow "any behavior" to occur). > An exception *MIGHT* be thrown, or > null might be returned, or any of several other possibilities. Not in DbC (sorry, but such a thing won't ever happen there). A failure in a runnable assertion *always* raises exceptions in DbC. In a defensive approach, anything can happen in a program. In a DbC approach, a false assertion raises exceptions. > > > > Another thing that puzzles me, is why do you keep arguing that > > runnable preconditions are not preconditions just because > > they do what is required to be done when an incorrect program > > is detected? > > I believe Daniel is taking the position that if "preconditions" are > runnable, then they are part of the well defined behaviour of the program, > and thus are part of the post-condition contract. I know he is. But I completely disagree with that messy view of contracts and program behavior. Preconditions are simply *pre*conditions: they are not part of *post*conditions. Exceptions are not part of the normal program behavior (hence they can be used to signal incorrectness). > It's not something I agree with though. Neither do I. > (IMHO,) whether something is a pre-condition or not depends on the > person writing the contract, Correct. > and NOT on the implementation of the method > that is supposedly fufilling that contract. Correct (and that is DbC approach). > For example, consider the following two methods: > > /* > pre-condition: s is not null. > post-condition: returns s. > */ > String foo(String s) { > return s; > } > > /* > pre-condition: none. > post-condition: returns s. > */ > String foo(String s) { > return s; > } > > Both of these methods satisfy their contracts. Both methods satisfy their part in the contract: the postconditions. By definition, there is no possibility for a method to satisfy its precondition (that is up to the clients). > But notice that the > implementation for both methods is exactly the same. Of course. The routine need only to be concerned to ensure its postconditions (always assuming its preconditions). > And yet, one of the > contracts has a pre-condition, and the other one doesn't. That is why preconditions and postcondition should be part of the routine's interface, not its implementation. Unfortunately most OO languages missed that essential point, and attach only prototypes to routines in interfaces (even in Ada, in which from the very beginning there was a lot of concern in separation implementation from interface, it is not possible to put these assertions in a module interface). > Therefore, I don't > think one should determine what the pre-conditions of a method are based on > the implementation of that method. The implementation will assume valid preconditions. Nowhere it should test them. > Therefore, with a program like this: > > /* > pre-condition: s is not null. > post-condition: returns s. > */ > String foo(String s) { > assert s != null; > return s; > } > > "s != null" is a runnable pre-condition. But it's also a "real" > pre-condition, in the sense that yes, this contract really does have a > pre-condition. Correct. > The contract didn't have to be designed this way; but that's > the way it was designed. The fact that the pre-condition is runnable does > not make it any less real. Exactly. In standard C++/Java/Ada we are forced to put assertion testing inside the routine implementation (a very unfortunate fact). (No such problem in Eiffel.) The problem is much (much) harder to express class invariants in those languages! > However, note that the following method also satisfies its contract: > > /* > pre-condition: none. > post-condition: returns s if it is not null, otherwise throws an > AssertionException. > */ > String foo(String s) { > assert s != null; > return s; > } > > So Daniel, I think, is saying that runnable pre-conditions can always be > converted to post-conditions. 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. It is completely absurd and useless to thing that "do_y" will receive a possible exception raised by foo (see my point?). The exception is there not necessarily for the direct client of the function, but to the program as whole to signal that an error has occurred. So a logical possible precondition for "do_y" can be a non-NULL String argument (never an exception as an entry "argument"). That is why it is so important to separate normal behavior from exceptional behavior. Our reasoning about the correctness of programs is much (much) easier and without ambiguities. > That part I agree with. I don't (and it is not DbC, which has been my point since the very beginning of this discussion). > But I don't agree with > the idea that this nescessarily means runnable pre-conditions are less real. > > > > > Also you seem to consider, for some reason, that exceptions are > > part of normal program behavior (reason why you insist in not > > fully understanding what I'm saying). That, in my opinion (and in > > DbC's), is a basic misunderstanding of this mechanism. > > Its existence is exactly to allow us to think and use two > > separated worlds: normal program behavior and exceptional > > behavior. In the former our primary objective is to reach > > correctness. The latter aims at robustness, either for a > > faster detection of errors and their correction, or for > > implementing fault tolerant techniques. > > See above. There's 3 worlds. Handling routine normal situations, > handling exceptional situations, and being incorrectly implemented. > Violating the pre-condition puts you in the "incorrectl implemented" world, > not the "handling exceptional situation" world. In DbC, an runnable assertion violation puts you in the exceptional world (in fact that is the exact justification for its existence). > > > >> (...) > > > >> Eiffel's pseudo-preconditions that really aren't because they have > >> defined behavior. > > > > A precondition is a condition expected to be observed > > before the routine starts its execution. Eiffel require clauses > > *are* preconditions (such as ensure clauses are postconditions > > and invariant clauses are invariants). > > I think Daniel is saying that Eiffel require clauses are implementation > detail which allows the programmer to cause the program to behave in certain > ways. They can be used to check pre-conditions, require clauses in Eiffel can only be used to check preconditions. > or they can be used to enforce post-conditions. No they can't. > They are not THEMSELVES pre-conditions; Yes they are (regardless of the fact that they can't always express the whole intended precondition). What you say is that, since exceptions have a known behavior (the program does something), then if they are expressed in a "contract" then the contract is not broken. A very confusing way to look at programs and contracts. In DbC exceptions are simply the program's behavior as a response to a detected broken contract (period). > they are tools for checking pre-conditions. Correct. > > > >> Please understand, I'm not deriding Eiffel here, I > >> think it is good to limit preconditions precisely because we can't > >> reason about the behavior of programs when they are not met (and we need > >> to be able to reason about the behavior of our programs.) > >> > >> > > Here, I've been talking about real preconditions, ones that > >> > > require being met or we cannot determine the outcome. > >> > > >> > All preconditions (postconditions, invariants and other assertions) > >> > are required to be met in correct programs. So I think I've been > >> > talking about the same things. > >> > > >> > DbC prescribes a very simple and precise behavior. > >> > If you have alternative practical proposals -based on > >> > the mathematical foundations in which most likely > >> > we all agree- I'm all ears. > >> > >> And therein lies the rub. "the behavior cannot even be considered" (you > >> know, that part you agreed to above?) means there is no solution, nor > >> can we even consider one. > >> > >> As such we must do our best to remove preconditions in our code and > >> provide well defined results for anything detectable. > > > > No. > > Yes. No. > The fewer pre-conditions your methods have, the fewer situations in > which the method will behave in an undefined manner, The *useful* work expected from a method is not to raise an exception. Preconditions are essential to make clear what is the usable work a method can produce. So, if you take that argument as a reason to weaken preconditions beyond reason, then you are in the defensive programming domain. Should my car accept sand as fuel? (It would be a weaker precondition.) Is the use of sand as fuel a defined behavior (just because someone wrongly choosed to include such a possibility in an incorrect precondition)? An "exception" raised by the car as a response to sand is not useful a behavior out of a car, it is simply a way to signal a wrong use of it (in the case of a precondition failure). As a programmer I try to put as much preconditions if my modules as possible. Many times I choose to not weaken them, because that makes the implementation of the module easier (and more efficient), and nothing is lost since the client can always choose the best module to do the work required. What would be profoundly wrong was not to make perfectly clear the contract, with a clear separation of obligations and benefits (for both sides). > and thus the more robust that method is. Our goal should be to make methods correct and programs reliable (correct+robust). The problem of robustness is beyond the scope of individual methods (it is a systemic property). It's part of the solution of the problem is simply to ensure exception in any assertion failure (simple, isn't it?). > > > >> Eiffel does this by creating a postcondition, > > > > No it doesn't. > > I won't get into this, since I think it's just a matter of choice of > words. You're both right. Preconditions and postcondition apply to different program parts (client and supplier), so to move conditions from one place to the other, is not simply a question of words (how can can a bad thing that happens in a program point be propagated ahead to another place which is after an alleged execution that will never occur, precisely because that bad thing has happened?). > > > >> "if a parameter is a certain value an > >> exception will be raised." > > > > That is not part of the postcondition (how could it > > be if the routine did not start its execution!). > > It is the exceptional behavior as a result of a failed > > precondition. > > > >> I'm fine with that, it's a great idea, but it > >> isn't a precondition > > > > Of course it is. It was a condition expected > > to be verified by the client *before* (as in *pre*) > > the routine starts its execution. In this respect, > > it is irrelevant if the error was found statically > > or at runtime. > > > > (References please.) > > > >> (which is a good thing, because preconditions are bad.) > > > > ? > > > > Preconditions, postconditions, invariants and other > > assertions are good. They make it quite clear > > what are the contracts expected, and they give > > us an idea of the meaning of programs (reusing > > Floyd's article title). > > Preconditions are bad, but specifying pre-conditions are good. Preconditions are "bad" for *clients*, and good for *suppliers*. Postconditions (and invariants) are good for clients, and "bad" for suppliers. It is not because we would like black boxes out of which we could get anything we want for any input (precondition: true), that makes preconditions bad (without the "'s). Preconditions are everywhere. Without them no one would know its responsibilities when using something. It is impossible to build machines without preconditions. It is impossible to use machines without postconditions. In programming we are constantly being clients *and* suppliers. > <analogy> > If I break my girlfriend's expensive vase, that's bad. If I admit to her > that I did it, and apolozie, that's good. > </analogy> Surely breaking the vase was not the precondition! The precondition would be probably *not* to break the vase (a good thing, if we don't want her to be in a very bad mood). The bad thing here was not to verify the precondition. > We should have as few preconditions as reasonably possible (we should > break as few vases as possible), If you didn't have the "do not break de vase" precondition, you could easily do the bad thing (break it) without being aware of the terrible mistake. > but any pre-conditions we are unable to > eliminate, we should should clearly specify (we should admit whenever we > break a vase instead of lying about it). Yes, preconditions should be explicit and clear. Anyway, it seems to me that you are, perhaps, confusing programs as a whole (which should be as bullet proof as possible) with their internal modules (which should be build to do useful work correctly). The idea of "eliminating" preconditions out of modules is named defensive programming (and it fails, because no matter what, not only a car will not be able to use sand as fuel, but also its clients will be very confused not being sure if that is the case). > - Oliver Best regards, -miguel -- Miguel Oliveira e Silva |