From: Miguel Oliveira e Silva on
"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
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
"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
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
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

First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Prev: Teaching OO
Next: multimethod + multiple inheritance