|
Prev: Teaching OO
Next: multimethod + multiple inheritance
From: Martin Brown on 28 Feb 2006 13:34 Daniel T. wrote: > In article <44035117.A32AC86E(a)det.ua.pt>, > Miguel Oliveira e Silva <mos(a)det.ua.pt> wrote: > >>Water Cooler v2 wrote: >> >>>Thanks for your diligent reply, Laurent. It has been very helpful and >>>interesting. >>> >>>I think I follow you and believe that my understanding has been correct >>>so far. What still intrigues me is: >>> >>>1. What then, are pre-conditions? >>> >>>My initial assessment showed they were conditions to test inside the >>>function's implementation, before the function returned valid input. If >>>they're not that, what are they? >> >>They are the client's part of the routine's contract. >> >>It is up to the client's to ensure a routine precondition >>*before* a call is attempted (however, a wise supplier >>should protect itself from erroneous preconditions, as >>explained below). > > A nice write up except for this one problem. If the supplier is able to > protect itself from erroneous inputs, then it can define proper outputs > for those inputs, thus making them no longer erroneous. > > Someone else's example: > > double inverse( double x ) { > return 1/x; > } > > The precondition of course is that 'x != 0' however, thats an easy thing > to check, and as such one can define a particular output for that > condition: > > // returns NaN if x == 0 > double inverse( double x ) { > return 1/x; > } Although you could specify it to return a silent NaN that merely delays detecting a hard error and contaminates other possibly meaningful future calculations that use this NaN result. Generating a trap in most cases would be preferable since it usually signifies a serious programming error when division by zero occurs. Your improved definition potentially breaks some code that might be expected to work algebraically since you can no longer satisfy the invariant property for the function inverse for all valid inputs. x == inverse( inverse(x) ) whereas 0 != inverse( inverse(0)) under your definition. And at present inverse(Nan) is also undefined. Returning a suitably signed infinity might just be defensible under some circumstances if the calculation must proceed and cannot be aborted. Regards, Martin Brown
From: Daniel T. on 28 Feb 2006 13:57 In article <du2530$jog$1(a)newsg4.svr.pol.co.uk>, Martin Brown <|||newspam|||@nezumi.demon.co.uk> wrote: > Daniel T. wrote: > > > In article <44035117.A32AC86E(a)det.ua.pt>, > > Miguel Oliveira e Silva <mos(a)det.ua.pt> wrote: > > > >>Water Cooler v2 wrote: > >> > >>>Thanks for your diligent reply, Laurent. It has been very helpful and > >>>interesting. > >>> > >>>I think I follow you and believe that my understanding has been correct > >>>so far. What still intrigues me is: > >>> > >>>1. What then, are pre-conditions? > >>> > >>>My initial assessment showed they were conditions to test inside the > >>>function's implementation, before the function returned valid input. If > >>>they're not that, what are they? > >> > >>They are the client's part of the routine's contract. > >> > >>It is up to the client's to ensure a routine precondition > >>*before* a call is attempted (however, a wise supplier > >>should protect itself from erroneous preconditions, as > >>explained below). > > > > A nice write up except for this one problem. If the supplier is able to > > protect itself from erroneous inputs, then it can define proper outputs > > for those inputs, thus making them no longer erroneous. > > > > Someone else's example: > > > > double inverse( double x ) { > > return 1/x; > > } > > > > The precondition of course is that 'x != 0' however, thats an easy thing > > to check, and as such one can define a particular output for that > > condition: > > > > // returns NaN if x == 0 > > double inverse( double x ) { > > return 1/x; > > } > > Although you could specify it to return a silent NaN that merely delays > detecting a hard error and contaminates other possibly meaningful future > calculations that use this NaN result. > > Generating a trap in most cases would be preferable since it usually > signifies a serious programming error when division by zero occurs. I have no problem with that, it's still a defined result. > Your improved definition potentially breaks some code that might be > expected to work algebraically since you can no longer satisfy the > invariant property for the function inverse for all valid inputs. > > x == inverse( inverse(x) ) > > whereas 0 != inverse( inverse(0)) under your definition. > > And at present inverse(Nan) is also undefined. We'd have to define that as well I guess. "ensure inverse(NaN) == 0" -- 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.
From: Dmitry A. Kazakov on 28 Feb 2006 14:00 On Tue, 28 Feb 2006 16:38:41 +0000, Miguel Oliveira e Silva wrote: > "Daniel T." wrote: > It seems to me, that you are incorrectly mixing the world > of normal program behavior, and the world of exceptions > and exceptional behavior. A behavior is either correct or not. A program exposing incorrect behavior is incorrect. [That correctness might be undecidable changes here nothing.] > Exceptions exist as a > mean to deal with (detectable) incorrect programs > (in DbC it is as simply as this). Exceptions are used for control flow in correct programs. Exceptions in incorrect programs are presumably incorrect. >> and as such one can define a particular output for that >> condition: >> >> // returns NaN if x == 0 >> double inverse( double x ) { >> return 1/x; >> } > > You surely can, but you surely shouldn't (or else > you will be doing defensive programming and not > DbC). Extended numeric sets are proven to be mathematically correct and deliver far safer and efficient computations than ones defined on bound numeric subsets. NaN is a *legal* value of IEEE float. It is a valid outcome of division a finite number by exact zero. Better could be only full-scaled interval arithmetic with infinity ideals. >> Now that's a *real* precondition. > > What do you mean by "real"? = used to determine correctness of the program. > (Surely you are not stating that runnable > preconditions are not real!) That is the only possibility, as I have shown in our previous discussion. I think there is no need to repeat it. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: Miguel Oliveira e Silva on 28 Feb 2006 14:59 "Dmitry A. Kazakov" wrote: > On Tue, 28 Feb 2006 16:38:41 +0000, Miguel Oliveira e Silva wrote: > > > "Daniel T." wrote: > > > It seems to me, that you are incorrectly mixing the world > > of normal program behavior, and the world of exceptions > > and exceptional behavior. > > A behavior is either correct or not. A program exposing incorrect behavior > is incorrect. [That correctness might be undecidable changes here nothing.] Agreed. > > Exceptions exist as a > > mean to deal with (detectable) incorrect programs > > (in DbC it is as simply as this). > > Exceptions are used for control flow in correct programs. Not in DbC. That would be an unacceptable abuse of exceptions. A correct program should never raise exceptions. In DbC, exceptions are used to deal with incorrect programs (broken contracts). > Exceptions in incorrect programs are presumably incorrect. Nope. They *correctly* signal an *incorrect* program (as in physical sciences when an experience whose results contradicts what was expected from a theoretical law, proves *correctly* that the law is *incorrect*). > >> and as such one can define a particular output for that > >> condition: > >> > >> // returns NaN if x == 0 > >> double inverse( double x ) { > >> return 1/x; > >> } > > > > You surely can, but you surely shouldn't (or else > > you will be doing defensive programming and not > > DbC). > > Extended numeric sets are proven to be mathematically correct and deliver > far safer and efficient computations than ones defined on bound numeric > subsets. NaN is a *legal* value of IEEE float. (So what?) I fail to see suitable uses of a NaN number ("Not-a-Number" number) other than to express an error within the number representation, but - by all means - be free to use that defensive approach to inverse [inverse(0) = NaN]. Just don't forget that the inverse function (as all functions) are is not an end in it selves, but a mean to reach somewhere. I'll bet that in 99.99...99% if the times the client of inverse is not expecting to divide by zero, neither such result makes any sense to whatever calculation required the use of this function. The class/routine implementor is free to set up whatever contract he wants. However, once defined, their clients are bound to observe them. So if the inverse function defines (as it should) the precondition of a non-zero argument, then we are in the presence of an incorrect program when x equals zero (regardless of the routine's postcondition). > It is a valid outcome of > division a finite number by exact zero. Better could be only full-scaled > interval arithmetic with infinity ideals. > > >> Now that's a *real* precondition. > > > > What do you mean by "real"? > > = used to determine correctness of the program. What? Are you saying that the non-zero x precondition of inverse is not useful to determine the correctness of a program? > > (Surely you are not stating that runnable > > preconditions are not real!) > > That is the only possibility, as I have shown in our previous discussion. (I missed that demonstration.) If that is your opinion, then don't call it DbC, or else you will be confusing everyone who does not know what is this methodology. > I think there is no need to repeat it. No it is not. It is only necessary a little effort to understand what I'm saying, and what DbC is. [B. Meyer, Object-Oriented Software Construction, 2ed, pages 331-438] > -- > Regards, > Dmitry A. Kazakov > http://www.dmitry-kazakov.de Best regards, -miguel -- Miguel Oliveira e Silva
From: Oliver Wong on 28 Feb 2006 15:47
"Miguel Oliveira e Silva" <mos(a)det.ua.pt> wrote in message news:4404AB97.37B38F68(a)det.ua.pt... > "Dmitry A. Kazakov" wrote: > >> On Tue, 28 Feb 2006 16:38:41 +0000, Miguel Oliveira e Silva wrote: >> >> > "Daniel T." wrote: >> >> Exceptions are used for control flow in correct programs. > > Not in DbC. That would be an unacceptable abuse of exceptions. > > A correct program should never raise exceptions. What if the contract specifically states that the behaviour of a given method is to raise an exception? E.g. /* Pre-conditions: None. Post-conditions: NullPointerException must be raised. */ void raiseNPE() { /*Implementation goes here*/ } > > In DbC, exceptions are used to deal with incorrect programs > (broken contracts). > >> Exceptions in incorrect programs are presumably incorrect. > > Nope. They *correctly* signal an *incorrect* program > (as in physical sciences when an experience whose results > contradicts what was expected from a theoretical law, > proves *correctly* that the law is *incorrect*). Not nescessarily, as shown above (i.e. the exception might correctly be part of the behaviour of a correctly implemented program). However, if a program is incorrectly implemented, then perhaps the exception raising routines are also incorrectly implemented, so raising the exception might not be a correct signal for anything! Another example: /* Pre-condition: none. Post-condition: "Hello World!" is printed to the standard out, no exception will be raised. */ void printHelloWorld() { print "Hello World!" throw new DivideByZeroException(); } This program is incorrectly implemented, and coincidentally an exception is raised. But the exception being raised is *INCORRECTLY* signalling the the incorrectness of the program; it claims that the problem had something to do with a division by zero, when that was not the nature of the incorrectness at all. Actually, the incorrectness was simply the presence of the exception itself! - Oliver |