|
Prev: Teaching OO
Next: multimethod + multiple inheritance
From: Daniel T. on 1 Mar 2006 09:10 In article <4404E104.CA725428(a)det.ua.pt>, Miguel Oliveira e Silva <mos(a)det.ua.pt> wrote: > "Daniel T." wrote: > > > In article <4404AB97.37B38F68(a)det.ua.pt>, > > Miguel Oliveira e Silva <mos(a)det.ua.pt> wrote: > > > > As in, "a require clause will cause an exception if its condition is > > false." This is very different from what happens if a precondition is > > not met. > > What do you propose that should happen in such situations? When a require clause's condition is false, it should throw an exception, because that is what require clauses are defined to do. I would never propose that a well defined construct do anything other than what it is defined to do. When a precondition is not met, we cannot propose anything because (as you agree to below,) we cannot even consider the behavior of the code. > > 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", yet you spend a lot of bandwidth considering what the behavior of the code should be when a precondition is not met... That's what I mean when I talk about "real" preconditions, as opposed to Eiffel's pseudo-preconditions that really aren't because they have defined behavior. 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. Eiffel does this by creating a postcondition, "if a parameter is a certain value an exception will be raised." I'm fine with that, it's a great idea, but it isn't a precondition (which is a good thing, because preconditions are bad.) -- 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: Daniel T. on 1 Mar 2006 09:26 In article <7fyp5pt4hnq7.1jec4c7748d0u$.dlg(a)40tude.net>, "Dmitry A. Kazakov" <mailbox(a)dmitry-kazakov.de> wrote: > Note also that the correct theory gives you much more, than you think. It > tells that run-time checks are the behavior [of the thing doing the > checks.] This is a very valuable knowledge, which instructs developers to > publish the checks in the contract. It also gives a rationale for layered > fault-tolerant software design with layers insulated against faults > underneath. Exactly because you cannot do much for correctness within one > layer. This is IMO *true* Design by Contract! Careful there, "Design by Contract" is trademarked, there is only One True DbC. -- 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: Oliver Wong on 1 Mar 2006 09:57 "Miguel Oliveira e Silva" <mos(a)det.ua.pt> wrote in message news:4404D2B9.176463A5(a)det.ua.pt... > Oliver Wong wrote: > >> >> What if the contract specifically states that the behaviour of a >> given >> method is to raise an exception? > > I understand what you Daniel and Dmitry are trying to > argue in this point. But as I several times attempted to call > up to your attention, DbC(tm) has a much simpler view of > contracts, normal program behavior and exceptions. > In DbC exceptions are simply the response of a program > to an incorrect behavior due to a broken contract. > > There is no need to put exceptions in contracts, because > in DbC when a runnable assertions is false an exception > is required to be raised. > > You may argue that exceptions can be used in normal > program control flow (in Eiffel its much harder to do that, > because, unlike Ada/C++/Java its exception mechanism > is tightly bound to DbC). However, I must insist that > such use is inappropriate (even in those languages). > Not only normal conditional instructions are much > more safe, expressive and efficient, but also it mixes > up two different programming worlds: the one bound > to the expected normal behavior of programs, and the > one used to get along with exceptional incorrect behavior. > > Also using exceptions for normal program control, > is little more than the disguise use of the unstructured > goto instruction (no more single point of entry and > single point of exit for program components). From my perspective, you have a view of "this is good enough for me, so it should be good enough for everyone". When I mentioned that testing the pre-conditions could break runtime performance requirements of a method, you said something along the lines of 99.99999% of programs are not real-time systems, and runtime performance isn't important except for real-time systems, for example. So I'm going to provide a few examples, but I fear you'll simply dismiss them as "well, these don't apply 99.99999% of the time." I think sometimes raising exceptions is a very legitimate part of the behaviour of a program, and not merely constrained to indicating incorrect programs. For example, let's say I'm writing a modular program which can accept plugins written by 3rd parties. I want to ensure that if the plugins screw up and throw exceptions, this doesn't bring down my whole application. Let's say I'm writing a unit testing framework (e.g. jUnit), I might create a method whose sole purpose is to throw an exception (e.g. assert[anything]()), so the exception is very much part of the normal behaviour of the program as well. Example: /* Pre-conditions: objects A and B implement an appropriate isEqual method. Post-condition: Throws an exception if A.equals(B) is false, or if exactly one of the objects is null. */ assertEquals(Object A, Object B) { if (A == null) { if (B == null) { return; } throw new AssertionException(); } if (B == null) { throw new AssertionException(); } if (A.equals(B)) { return; } throw new AssertionException(); } - Oliver
From: Oliver Wong on 1 Mar 2006 10:04 "Dmitry A. Kazakov" <mailbox(a)dmitry-kazakov.de> wrote in message news:7fyp5pt4hnq7.1jec4c7748d0u$.dlg(a)40tude.net... > Note that double (assuming IEEE float) and, say, DEC floating-point type, > are different types with different sets of values! It is *incorrect* to > raise an exception for double 1/x because 1/0 is *defined* to return NaN > for 1/0. Defined here, is in strict mathematical sense. If you take > another > type, with the domain set limited to only real numbers (like DEC > floating-point is), then exception would be appropriate. 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. (negative) infinity divided by (negative) infinity is equal to NaN. Maybe infinity minus infinity is also NaN, but I'm not sure about this last one. - Oliver
From: Oliver Wong on 1 Mar 2006 10:08
"Miguel Oliveira e Silva" <mos(a)det.ua.pt> wrote in message news:4404ED6B.CFB9753E(a)det.ua.pt... > "Dmitry A. Kazakov" wrote: >> What could an *incorrect* >> program *correctly* do about anything? > > Terminate execution (identifying the error); > or propagate the exception upwards in the > call stack until a point in which it would be > safe to retry an alternative (hopefully, correct) > algorithm (fault tolerance). You seem to be missing the point here. The program is incorrect. So you look at the source code, and somewhere, it contains bugs, but you're not sure where yet. You look at the source code, and you *THINK* what it will do is terminate execution or propagate the exception upwards in the call stack until a point in which it would be safe to retry an alternative algorithm... but maybe it won't! Why not? Because it's incorrect! This is what is meant by "You cannot say anything about the behaviour of an incorrect program." You might WANT it to terminate; but it won't nescessarily do so! - Oliver |