From: Oliver Wong on

"Miguel Oliveira e Silva" <mos(a)det.ua.pt> wrote in message
news:440712A1.1B61BC5C(a)det.ua.pt...
> Oliver Wong wrote:
>
>> /*
>> 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).

I think there was a miscommunication about the pre-condition here. The
string called filename must be a valid filename. There may or may not exist
a file with such a name. The pre-condition only asks that the filename is
valid for the given OS (e.g. "*" is not a valid filename in Windows). If the
filename is valid, but there does not exist such a file, then the
pre-condition is NOT violated.

Can you re-respond to my previous example with this new understanding in
mind?

[...]
>>
>> 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.

I'm not sure of what programming language you're thinking of, but in the
ones I'm aware of, if foo(s) throws an exception, this exception will not be
"received" by do_y(). The exception moves up the call stack, and execution
stops unless there's an apporpriate catch statement.

[...]

>> They are not THEMSELVES pre-conditions;
>
> Yes they are (regardless of the fact that
> they can't always express the whole intended
> precondition).

I think we're getting into philosophy here. It's like me saying "red" is
not actually the colour red, but a string whose semantical contents refer to
that colour.

(IMHO) Eiffel require-clauses aren't themselves pre-conditions, but
rather Eiffel's particular implementation of allowing you to encode the
pre-conditions of a method into the source code representation of that
method. Again, to me it's just a minor philosophical point, so I'm happy to
agree to disagree on this one.

>
> 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).

If this is true, then DbC is useless in all cases where the
contract-designer explicitly wants exceptions thrown under certain
conditions.

[snip]
>
>> 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.

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.

You might write a function which takes as input an error code, and as a
result, raises the corresponding exception.

void convertToException(int i, Object errInfoObject) {
if (i == 1) {
throw new DivideByZeroException();
}
if (i == 2) {
String filename = (String)errInfoObject;
throw new FilNotFoundException(filename);
}
//etc.
}

You seem to be neglecting that exceptions may be a very useful part of
program behaviour, and not just for ensuring the correct of the program.

>
> 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. This isn't a very realistic example, but perhaps
the principle ideas will be clear anyway.

Suppose that you have a car, and there's a pre-condition on it saying
that "sand shall not be used as fuel". Now say you are being held hostage by
a terrorist, and he tells you at gunpoint to pour sand into the gas tank of
the car. You will be relunctant to do this, because you have NO IDEA what
will happen if you put sand into the gas tank of the car. Perhaps doing so
will magically cause the death of billions of innocent people, including
your family and loved one. There really is no information that you can
derive from the consequences of pouring sand in there. Perhaps pouring the
sand in there will somehow magically cause your own death, in addition to
the death of others, in which case you should refuse, since either way
you'll die, but by refusing to comply with the terrorist, you'll be saving
billions of lives.

Now suppose you have a car, and it has a POST condition saying "if sand
is used as fuel, this will result in the malfunctioning of the car." Then
the terrorist holds a gun to your head and tells you to pour sand in the
fuel tank. You will immediately comply, because you know what the results of
your actions are, and you consider the car to be less valuable than your
life.

It's better to have accurate information than no information.

>
> 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).

I claim that there exists situations where this IS useful.

>
> 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.

I wear two hats. One is the "contract-writer", where I balance the
interest of both parties: the client, and the implementor. What does the
client want out of this contract? What pre-conditions does the implementor
want in exchange for implementing this contract? Does the client find this
acceptable? Great.

Now I switch hats, and am the implementor. I see what pre-conditions I
can work with, and what post-conditions I must fufill, and work with them.

The problem with "putting as much preconditions as possible to make
implementation easy" is that with that, you can do anything (including the
impossible). 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() {
}

Writing contracts really has to be a negotation between the two parties,
even if the two parties are both you (i.e. you're writing both the
implementation of the method, and the client code which will call the
method).

> What would be profoundly wrong
> was not to make perfectly clear the contract, with
> a clear separation of obligations and benefits (for
> both sides).

Agreed.

>
>> 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?).

The fewer pre-conditions, the more robust that one particular method is.
The more robust each individual method in a system, the more robust that
system is as a whole, etc.

[...]

>>
>> 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.

Yes, sorry, I should have made it clear that I was talking about the
client's point of view here. And client-satisfaction is important for the
suppliers.

Again, look at my halting-problem solver, posted above. This has the
best possible pre-condition, and yet it's BAD for the supplier. Why? Because
no client will ever use the method. So the effort I spent writing that
method was wasted.

>> <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.

I'm not saying that "the vase must be broken" is a precondition. I'm
saying that preconditions are bad (for the client), just like breaking vases
are bad (for the owners of the vase). The above analogy is not about
contracts or programming, so pre-conditions aren't within that analogy. They
are what the analogy is trying to compare itself too.

<meta-analogy>
It's like when someone makes an analogy between software and cars, and
someone says "but my webbrowser doesn't have tires."

Yes, I know it doesn't have tires. It was just an analogy.
</meta-analogy>

;)

>
> 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).

Well, to me, the names of things aren't so important as the things
themselves, but if you want to call it defensive programming, fine. Using
your definitions, I claim that DbC is good, but it's better when used in
combination with "defensive programming".

- Oliver

From: Miguel Oliveira e Silva on
Oliver Wong wrote:

> "Miguel Oliveira e Silva" <mos(a)det.ua.pt> wrote in message
> news:440712A1.1B61BC5C(a)det.ua.pt...
> > Oliver Wong wrote:
> >
> >> /*
> >> 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.
> >
> > 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).
>
> I think there was a miscommunication about the pre-condition here. The
> string called filename must be a valid filename.

Sorry, I assumed that it was a filename referring to an existing
readable file.

If that was not the idea, perhaps it should have been,
or else the name of the function should be: tryToOpenFile.

> There may or may not exist
> a file with such a name. The pre-condition only asks that the filename is
> valid for the given OS (e.g. "*" is not a valid filename in Windows).

Ok.

> If the filename is valid, but there does not exist such a file, then the
> pre-condition is NOT violated.

Correct.

> Can you re-respond to my previous example with this new understanding in
> mind?

The inexistence of a readable(/writable?) file attached
to "filename" is a very possible normal behavior when
handling with files. OpenFile should require the existence
of the filename it is supposed to open.

Your DbC file module should be something like (Eiffel syntax):


class FILE

feature

valid_name(name: STRING): BOOLEAN
require
name /= Void

exists(filename: STRING): BOOLEAN
require
filename /= Void;
valid_filename(filename)

readable(filename: STRING): BOOLEAN
require
filename /= Void;
valid_name(filename);
exists(filename)

open_to_read(filename: STRING)
require
filename /= Void;
valid_name(filename);
exists(filename);
readable(filename)
ensure
opened_to_read

read_integer: INTEGER
require
opened_to_read
(...)

end -- FILE


This way you'll be certain that the clients
of this module can (and must) check file
existence and readability, before an attempt
to open the file.

It is true that in file handling there can
exist various race conditions due to
external noxious concurrent accesses
to files (which can happen anytime
during file operations).
So the precondition "file_exists" will
not give 100% assurance that a millisecond
latter the file still exists! However, the
programmer can (and should) assume
that this race conditions are very rare
situations, and include them inside
the realm of program errors, making
them to trigger exceptions (false
precondition).

You may ask: If such a thing might happen,
why not then implement "OpenFile" without
all those preconditions?

Well, the reason is (again) program correctness.
If you expect that, in normal program behavior,
exceptions will arise, then to reason and
assert about the correctness of the program
will be much harder. You'll also be forced
to consider goto-like exceptions as normal
program behavior. That is a very messy
world (perhaps then, it would be useful a
meta-exception mechanism to signal
errors in the exception world).

If a program is logically correct, it is
expected that before a call to "OpenFile"
somewhere in the (normal) program
there was a verification that the file
exists and is readable.
Such as reading a file should only occur
after an OpenFile (and before a CloseFile).

Of course it doesn't have to be the way I'm saying,
and you are free to express more permissive
contracts. In my experience it pays off
to leave normal behavior out of exceptions.


There is a kids tail about a shepherd who
was constantly joking about a coming
wolf. The first and second time he did that,
everyone believed him, and measures were
taken to protect his herd. However, realizing
that it was a recurrent joke, they cease to
believe in anything he said. One day the
wolf really came, and his herd was killed.

Exceptions should not be abused.
They have a very clear goal: signal
incorrect behavior. Programs are
much more readable, clean and
simple if we keep things that way.

(I've seen too many Java/C++ programs
in which exceptions are cached just
to print an error message, and let the
program to go on as if nothing has happened.
Clearly the same problem as the shepherd.
Isn't it?)

> [...]
> >>
> >> 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.
>
> I'm not sure of what programming language you're thinking of,

None. I was showing the absurdity of putting exceptions inside
the postcondition contract (argument by absurd).

> but in the
> ones I'm aware of, if foo(s) throws an exception, this exception will not be
> "received" by do_y().

Precisely my point. It is a signal to the program, not necessarly
to the direct client of the function.

> The exception moves up the call stack, and execution
> stops unless there's an apporpriate catch statement.

Right.

> [...]
>
> >> They are not THEMSELVES pre-conditions;
> >
> > Yes they are (regardless of the fact that
> > they can't always express the whole intended
> > precondition).
>
> I think we're getting into philosophy here. It's like me saying "red" is
> not actually the colour red, but a string whose semantical contents refer to
> that colour.
>
> (IMHO) Eiffel require-clauses aren't themselves pre-conditions, but
> rather Eiffel's particular implementation of allowing you to encode the
> pre-conditions of a method into the source code representation of that
> method. Again, to me it's just a minor philosophical point, so I'm happy to
> agree to disagree on this one.

If you say that they do implement preconditions, we agree.

> >
> > 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).
>
> 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.

> [snip]
> >
> >> 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.
>
> 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).

> You might write a function which takes as input an error code, and as a
> result, raises the corresponding exception.
>
> void convertToException(int i, Object errInfoObject) {
> if (i == 1) {
> throw new DivideByZeroException();
> }
> if (i == 2) {
> String filename = (String)errInfoObject;
> throw new FilNotFoundException(filename);
> }
> //etc.
> }

> You seem to be neglecting that exceptions may be a very useful part of
> program behaviour, and not just for ensuring the correct of the program.

I am not neglecting it. I am saying that they should never be used
for normal correct program behavior (that's DbC philosophy).

> >
> > 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).

> This isn't a very realistic example, but perhaps
> the principle ideas will be clear anyway.
>
> Suppose that you have a car, and there's a pre-condition on it saying
> that "sand shall not be used as fuel".

Preconditions assert what the module expects and requires.
Not what the module does not expect or requires (or else,
it would be a very, very long list of conditions).

> Now say you are being held hostage by
> a terrorist, and he tells you at gunpoint to pour sand into the gas tank of
> the car. You will be relunctant to do this, because you have NO IDEA what
> will happen if you put sand into the gas tank of the car. Perhaps doing so
> will magically cause the death of billions of innocent people, including
> your family and loved one. There really is no information that you can
> derive from the consequences of pouring sand in there.

If the car has a runnable precondition (whatever that might be
in a car!) of (fuel = gasoline), nothing will happen, if the
car behavior is not fault tolerant it will simply cease to work.

> Perhaps pouring the
> sand in there will somehow magically cause your own death, in addition to
> the death of others, in which case you should refuse, since either way
> you'll die, but by refusing to comply with the terrorist, you'll be saving
> billions of lives.
>
> Now suppose you have a car, and it has a POST condition saying "if sand
> is used as fuel, this will result in the malfunctioning of the car." Then
> the terrorist holds a gun to your head and tells you to pour sand in the
> fuel tank. You will immediately comply, because you know what the results of
> your actions are, and you consider the car to be less valuable than your
> life.

It is not necessary to put it in the postcondition. If the precondition
if (fuel = gasoline), that is enough to ensure that nothing bad will
happen (if the car software were allowed to control car behavior,
it wouldn't even start, preventing an attempt to burn sand).

> It's better to have accurate information than no information.

Preconditions are accurate information.

> >
> > 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).
>
> I claim that there exists situations where this IS useful.

(Aren't you taking this absurd example a little too far away?)

> >
> > 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.
>
> I wear two hats. One is the "contract-writer", where I balance the
> interest of both parties: the client, and the implementor. What does the
> client want out of this contract? What pre-conditions does the implementor
> want in exchange for implementing this contract? Does the client find this
> acceptable? Great.
>
> Now I switch hats, and am the implementor. I see what pre-conditions I
> can work with, and what post-conditions I must fufill, and work with them.
>
> 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.

> 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.

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).

Any program that attempts to use
solveHaltingProblem is simply
incorrect (incorrect is not equal
to solve the halting problem).

> Writing contracts really has to be a negotation between the two parties,
> even if the two parties are both you

Correct.

> (i.e. you're writing both the
> implementation of the method, and the client code which will call the
> method).
>
> > What would be profoundly wrong
> > was not to make perfectly clear the contract, with
> > a clear separation of obligations and benefits (for
> > both sides).
>
> Agreed.
>
> >
> >> 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?).
>
> The fewer pre-conditions, the more robust that one particular method is.

At the expense of a less robust program/system.

(Robustness is a systemic property.)

> 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.

> [...]
>
> >>
> >> 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.
>
> Yes, sorry, I should have made it clear that I was talking about the
> client's point of view here. And client-satisfaction is important for the
> suppliers.

(Absolutely essential.)

> 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).

Don't forget that preconditions *precede* postconditions.
That's why there is no paradox there.

> Why? Because
> no client will ever use the method. So the effort I spent writing that
> method was wasted.

(Well, it was your method, not mine ;), so I don't think that's
my problem. You could have done nothing, and still you would
have keep your part of the contract.)

> >> <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.
>
> I'm not saying that "the vase must be broken" is a precondition. I'm
> saying that preconditions are bad (for the client),

But they aren't (In case you haven't noted I wrote "bad", not bad).

Preconditions are good also to the clients, because they won't
be fooled by expecting impossible things out of routines.

> just like breaking vases
> are bad (for the owners of the vase).

No, it is not "just like". Breaking vases is definitely bad (program error).
But the problem was not the precondition (it's the way things work).

> The above analogy is not about
> contracts or programming, so pre-conditions aren't within that analogy. They
> are what the analogy is trying to compare itself too.

(If you look more carefully you will see many preconditions hanging
there, and everywhere [like in a "nightmare": there is no escape,
no matter how deeper we put our head inside the sand]).

> <meta-analogy>
> It's like when someone makes an analogy between software and cars, and
> someone says "but my webbrowser doesn't have tires."

> Yes, I know it doesn't have tires. It was just an analogy.
> </meta-analogy>

> ;)

;)

> >
> > 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).
>
> 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?

Names are essential for a noise-free communication.
Hence to be able to understand, to teach, and to learn.

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.

> but if you want to call it defensive programming, fine. Using
> your definitions, I claim that DbC is good, but it's better when used in
> combination with "defensive programming".

They are opposing methodologies (it will be hard to combine them).
(They prescribe opposing medicines.)

Defensive programming is a good methodology to handle
conditions that are completely outside the program's
responsibility, such as when communicating with the
external world.

> - Oliver

Best regards,

-miguel

--
Miguel Oliveira e Silva

From: Dmitry A. Kazakov on
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. 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.

--
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: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.

[...]
>> 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, because of the "dirt" leaking in. 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.
(e.g. one where exceptions are allowed as part of the normal behaviour of
the module).

>> >
>> > 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. If you
have a pre-condition "A", then the information you have is "If A is false, I
don't know what happens." If you have a post-condition "if A is false, car
fails", then you now have more information than before, and that's better.

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.

The problem with the "no sand" precondition 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).

But if the engineers are confident that they can guarantee that a car
will ALWAYS fail to run when given sand as fuel, 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.

[...]
>>
>> 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.

>
>> 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.

>
> 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).

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!";
}

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*.


>
> 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. Here's a different contract, for example:


/*
pre-condition: false
post-condition: prints "Hello World" to standard out.
*/
void printHelloWorld() {
print "Goodbye.";
}

This method also satisfies its part of the contract, 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; I claim it is completely free of bugs. It does exactly what it is
intended to do!

The exact same thing is happening with my "solve halting problem"
function above. It does exactly what it intends to do, which is to solve the
halting problem, given certain assumptions and pre-conditions.

>
>> 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. The fewer assumptions the implementor makes, the
more robust the implementation. Therefore, the LESS pre-conditions, the more
robust the program.

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, 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.

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.

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.

>>
>> 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.

English isn't as rigorous as one would like, so you will often find
people disagreeing about the meanings or definitions of terms. 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.

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.

- Oliver

From: ggroups on
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 ...


Regards,
Steven Perryman

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