From: Miguel Oliveira e Silva on
Oliver Wong wrote:

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

Oliver, DbC prescribes a very simple (but not simplistic)
view of programming. Modules (classes) should be
built with clear and explicit contracts. Contracts express
the module correctness assertions. Hence a broken
contract is always the manifestation of an incorrect
program (we most likely agree to this point).

So what DbC imposes is that a false runnable
assertion *always* raises an exception (ok?).
It does not strictly forbids you from using
exceptions for other objectives. No language,
even Eiffel, cannot prevent such a thing to
happen (although in Eiffel, due to its disciplined
exception mechanism, the programmer
is forced to do that explicitly on purpose
avoiding same nasty program errors).

However, a wise programmer, should not
use exceptions to deal with situations that
can easily be dealt with normal language
instructions, or else sooner or later he
no longer will know if exceptions
are exceptional, or simply another
normal control structure (= goto).

We can identify two important situations
where exceptions are the appropriate
tool: (internal) broken contracts, and abnormal
behavior due to external unpredictable
erroneous situations (not completely
controllable by the program). This last
case can be thought as been an external
broken contract (for example, after
testing the existence of a file inside
a program one expect the postcondition
that the file exists!). In the latter case,
a reliable program will need to use
the exception mechanism to ensure
the correctness of the program (my
mistake for not remembering, in previous
messages, this rare but, nevertheless,
important situation).

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

Not at all.

They can be fully DbC compliant (why shouldn't they?).

> because of the "dirt" leaking in.

But it does not "leak out" (that's the point), so external
clients will use a 100% compliant DbC module.

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

I'm not sure you completely understand "my" definition of DbC.
DbC is a sufficient methodology to build programs. You are free
to put, or remove, conditions from contracts.

My advise is that contracts should be reasonable, and assertions
should express only correctness program conditions (not exceptional
behavior as a result of a program error). If you do want to put
exceptional behavior inside contracts (which may not go against
DbC), DbC just requires that you don't mix different assertions,
and that a false assertions always raises exceptions.
Preconditions cannot be expressed as postconditions.

> (e.g. one where exceptions are allowed as part of the normal behaviour of
> the module).

You mean: when an exceptional behavior is a normal behavior?

(Why call it exceptional then?)

Please don't think I'm playing with words. Exceptions exist
for a reason. And that reason is not to replace goto's.

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

No it doesn't.

(See my response to that in the end of this message, when
I compare your contracts A and B).

> If you
> have a pre-condition "A", then the information you have is "If A is false, I
> don't know what happens."

If it is runnable, an exception is raised (that is not undefined
behavior: it is simply an *exceptional* behavior).

> If you have a post-condition "if A is false, car
> fails", then you now have more information than before, and that's better.

Oliver, it is impossible to express all the conditions that should
not happen (sand/water/rocks/.../garbage as fuel), so your
suggestion is absurd. In contracts, one is bound to express
what is required at the start (precondition) and what
will arise in the end (postcondition).

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

Take a little time to think about it. You'll surely see that's
absurd.

The (runnable) precondition (fuel = gasoline) is more than
enough to completely protect the car against other absurd
types of fuel.

> The problem with the "no sand" precondition

There is not a "no sand" precondition (where did you
saw such a thing?). The precondition is (fuel = gasoline).

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

Of course. In the gasoline car abstraction, sand will
never be an acceptable fuel.

You can, however, create ADTs for more abstract cars.
In fact we can simply use the static type system to
solve the fuel problem with generic classes:

class CAR[F -> FUEL_TYPE]

feature

fuel_capacity: DOUBLE; -- maximum amount of fuel possible

fuel_level: DOUBLE; -- current amount of fuel

fill(amount: DOUBLE) is
require
amount > 0;
fuel_level + amount <= fuel_capacity
ensure
fuel_level = old fuel_level + amount
....
invariant

fuel_capacity > 0;
fuel_level >= 0 and fuel_level <= fuel_capacity;

end -- CAR

The class FUEL_TYPE would be an abstract
class from which all types of fuels would be
required to inherit in order for a CAR to be used.

BTW, in Eiffel CAR[F -> FUEL_TYPE] means
that CAR is a generic (template) class which
only accepts as type parameters types descendant
from FUEL_TYPE (hence it is ensured statically
that no SAND will ever be used as fuel, unless
in the future such a propelling fuel is invented).

> But if the engineers are confident that they can guarantee that a car
> will ALWAYS fail to run when given sand as fuel,

Of course, in my initial analogy, the precondition
was (fuel = gasoline).

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

(Not again, please!)

The condition *precedes* the usage of the car, hence it is a *pre*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.

The supplier is only required to do things *iff* preconditions are met.
With a false precondition he can do whatever he likes, including
nothing. The contract will fail due to the client's responsibility.

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

(Who is playing with words now?)

A false precondition (as you recognize below) cannot be met.
And that fact is not *besides the point*. It is *the* point.
(That is why there is a "pre" in preconditions and a
"post" in postconditions.)

(Perhaps the way you view this problem
results from that messy way of viewing
contracts, in which you insist in putting
broken preconditions as defined behavior
in postconditions.)

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

(Only in your apparently confused mind.)

The supplier knows that the precondition is never
met, so he can do anything he wants inside the
routine. He also knows that nobody will never
try to see if the postcondition is met (so he's
off the hook).

In case you haven't notice, postconditions are
not evaluated alone. They are an implication
from preconditions. This basic causal relation
is not "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!";
> }

Same thing as the other one.

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

*Only* a beginner programmer could say that.
Preconditions cannot be ignored by clients.
A client will never know if the supplier mets
the postcondition.

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

When you put a false precondition in a solveHaltingProblem
routine, saying that it solves the problem, then you are
indeed saying that incorrect program = 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.";
> }

(Same thing.)

> This method also satisfies its part of the contract,

The contract is, by definition, broken if any client
attempts to use this function. The responsibility
for this very unfortunate fact belongs to the client.
It is absolutely irrelevant the conditions expressed
in *post*conditions.

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

By definition, with a false precondition, we will never
know if the supplier is incorrect (before that, the client
has already be proved guilty).

> I claim it is completely free of bugs.

Really! A false precondition = free of bugs.
(I'm always learning new extraordinary things.)

> It does exactly what it is intended to do!

Of course: a program error (which is *not* to print "Hello World",
then halting problem, or whatever you might like to put *after*
a false assertion).

> The exact same thing is happening with my "solve halting problem"
> function above.

Exactly.

> It does exactly what it intends to do, which is to solve the
> halting problem, given certain assumptions and pre-conditions.

(Think again.)

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

Correct.

> The fewer assumptions the implementor makes, the
> more robust the implementation.

Not quite.

If we can weaken preconditions and still do useful
work (which rules out: raising exceptions), then the
routine will be able to serve correctly wider requests
from clients (which is good, because it will be a
more general routine).

However, the problem is that almost always,
a routine cannot do useful work out of every
request from clients. The robustness problem
arises precisely from this problem (to request
impossible things to routines).
Reliability is ensured when *everyone*
mets their part of the contract (not just the
clients, but also suppliers).

So a reliable program is one in which all
assertions are either met (correctness),
or, if tested to be false, raises an exception
(DbC view of broken contracts).

What you don't seem to fully understand
is that, no matter what, when one wants
to do useful work inside a routine there
is almost always a precondition involved,
and the problem is not the existence of
the precondition, but the limitations
we have to put things to work correctly.
That was the case of "sqrt", "inverse",
the car analogy, and almost any other
problem you might think off.

For same reason that escapes me (but I
keep an opened mind[*]) apparently
you seem convinced that because you
put in a postcondition an exceptional
behavior, there is no precondition
involved. The precondition is there,
it is simply hidden in the wrong place,
with nasty consequences (see the end of
the message).

[*] but not so open that my brain fall out.
(to cite Carl Sagan)

> Therefore, the LESS pre-conditions, the more
> robust the program.

The better contracts are met by everyone
the more correct (so also more reliable) the
program is (which is not the same as less
preconditions).

The more you allow false assertions to
not raise exceptions, the less robust your
program is.

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

It is not.

The contract is part of the public ADT of a module.
Once established, the clients know their part of the
deal and are also ensured on the module's
responsibilities.

That is why contracts are required to be inherited
by descendant classes (Eiffel does that by default,
in other languages it required much more handmade
bookkeeping work by the programmer to approach
that essential behavior).

A contract cannot be changed lightly, neither
by clients nor by suppliers (or else correctness
problems will arise).

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

It was not me who putted as an (absurd) example a
routine with a false precondition, so it is not up
to me to answer that question.

> But I guess it's useless to proceed further with this until we define
> metrics for "good" and "bad" for the supplier and client.

They are very easy to define. All true assertions are good, and
all false assertions are bad.

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

Correct.

> It is GOOD for the supplier if he can find a client who will agree to a
> contract with the supplier.

Correct.

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

That's irrelevant.

Since the false assertion is a precondition, that routine
is simply bad for clients (that's why they shouldn't use it).

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

True.

> English isn't as rigorous as one would like, so you will often find
> people disagreeing about the meanings or definitions of terms.

Agreed.

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

Same with me.

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

In contract B the precondition should have been the same
as in A: (s != NULL).
You just made the mistake to hide it inside the postcondition
(wrongly making the clients belief that the routine can do
useful work regardless of the value of s).

Contract B, is much (much) worse than A's because,
if s happens to be NULL, the client is not ensured (since
the exceptional behavior is in the postcondition) that
the routine did not do nothing else besides raising an
exception. Hence he may lose the extremely important
guarantee that the supplier object invariant is still correct
even if the exception was raised (DbC ensures that).
That's a very (very) serious problem resulting
from putting the (exceptional) behavior of broken
preconditions inside postconditions.

Another serious problem with B's like contracts
happens when the programmer misses an
exceptional behavior in postconditions for
some runnable (hidden) precondition.
The client knows that such a precondition
exists, but he will be unsure if the supplier
will indeed respond with an exception.
Isn't it much simpler to take that for
granted as in DbC (without moving
assertions to wrong places)?

Tell me, why do you put exceptional behavior
inside postconditions, and not inside preconditions?
(Which would bring your normal *and* exceptional
behavior to match DbC.)

Afterall, the exception was caused by something
that the client did (s=NULL), and not as a result
of something inside the supplier's code. (Do we
agree in this point?)

Again, DbC approach is much simpler and safe:
any detected false assertion raises an exception.

> - Oliver

Best regards,

-miguel

--
Miguel Oliveira e Silva

From: Oliver Wong on

<ggroups(a)bigfoot.com> wrote in message
news:1141384594.168474.257720(a)z34g2000cwc.googlegroups.com...
> 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 ...

The problem with this is that if it were true that it's best for the
supplier to implement components with the strongest pre-conditions and the
weakest post-conditions, then no one would ever implement any component
except for this one:

/*
pre-condition: false.
post-condition: does nothing
*/
void doesNothing() {
}

But why isn't that what we observe in real life? Because there's an
ADDED factor that a supplier will not want to waste his/her time
implementing a component that no one wants to use! That's the point I was
trying to make.

- Oliver

From: Dmitry A. Kazakov on
On 3 Mar 2006 03:16:34 -0800, ggroups(a)bigfoot.com wrote:

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

Maybe, but there is also somebody who assigns suppliers and consumers,
responsible for the problem decomposition. Now the question is, when the
negotiation takes place. Before or after the roles have been identified?

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
From: Miguel Oliveira e Silva on
"Dmitry A. Kazakov" wrote:

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

You assume that exceptions raised due to false preconditions,
disguised as a postcondition, are part of a correct program.
I do not (is this reasonable to you?).

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

Correct.

My point, is that P3 is not part of "do_y"'s precondition
(an exception is never a precondition of normal
routines/instructions, only for catch/rescue blocks).

So I was using a "reductio ad absurdum"
argument, in which I attempted to show
that exceptional behavior (being goto like)
is outside normal structured (single entry
and exit points) view of programs.

So, exceptions are required to take into
consideration code outside normal
program structured instructions
(as you did, by including a possible
catch block). Using them for normal
program behavior is not a structured
approach, hence it makes it much
harder to reason on program
correctness.

> --
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de

Best regards,

-miguel

--
Miguel Oliveira e Silva

From: Oliver Wong on

"Miguel Oliveira e Silva" <mos(a)det.ua.pt> wrote in message
news:44087328.68DFA1A7(a)det.ua.pt...
> Oliver Wong wrote:

[snipped everything except Contract-A and contract-B, which seems to be the
core issue now]

>> 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.
>
> In contract B the precondition should have been the same
> as in A: (s != NULL).
> You just made the mistake to hide it inside the postcondition
> (wrongly making the clients belief that the routine can do
> useful work regardless of the value of s).

Whether something is "useful" or not depends on the client's opinion.
Perhaps the client specifically wants a NullPointerException (and not ,
e.g., AssertionException) to be thrown when s is equal to null, and
therefore B is MORE useful than A.

A does not specify what will happen if s is null. If the client is
writing code which critically depends on NullPointerException being thrown
when s is null, then the client MUST use B, and CANNOT use A.

If the client will never set s = null, the nthe client can use either B
or A, as they will both perform identically for all situations the client
will encounter.

That is why I say any client who accepts contract A will also accept
contract B.

>
> Contract B, is much (much) worse than A's because,
> if s happens to be NULL, the client is not ensured (since
> the exceptional behavior is in the postcondition) that
> the routine did not do nothing else besides raising an
> exception. Hence he may lose the extremely important
> guarantee that the supplier object invariant is still correct
> even if the exception was raised (DbC ensures that).
> That's a very (very) serious problem resulting
> from putting the (exceptional) behavior of broken
> preconditions inside postconditions.

This is a problem with all contracts: post conditions generally don't
list all the things they DON'T do. E.g.:

/*
Pre-condition: None.
Post-condition: Returns true. Does not emit anything to standard out. Does
not allocate RAM. Does not kill children. Does not cause your car to
explode. Etc.
*/
bool getTrue() {
return true;
}

Usually, if a contract does not mention behaviour Foo, it can safely be
assumed that the method will NOT do contract Foo. If this is a problem for
the client, the client should negotiate a new contract where the desired
behaviour is made explicit.

Contract B says that the method will return s except when s is null, in
which case it will throw NullPointerException. Note that the post-condition
does not say things like "BTW, I am free to violate any class constraints,
etc." And because it doesn't say that, it won't do that.

Exceptions do not indicate that class invariants might have been
violated. This fear is unjustified.

>
> Another serious problem with B's like contracts
> happens when the programmer misses an
> exceptional behavior in postconditions for
> some runnable (hidden) precondition.
> The client knows that such a precondition
> exists, but he will be unsure if the supplier
> will indeed respond with an exception.
> Isn't it much simpler to take that for
> granted as in DbC (without moving
> assertions to wrong places)?

There is NO pre-condition in contract B. Not even a hidden one. I don't
know why you say there is. If the client "knows" that such a pre-condition
exists, then that client has obviously misunderstood the contract. There is
not pre-condition.

If the client carefully reads the contract, he will see that the
behaviour of the method is to return s when s is not null, and to throw
NullPointerException when s is null.

The client therefore knows the behaviour of the method in the cases
where s = "Dog", s = "Hello World!", s = null, and an just about every other
situation that will arise. The behaviour is explicitly stated in the
contract.

>
> Tell me, why do you put exceptional behavior
> inside postconditions, and not inside preconditions?
> (Which would bring your normal *and* exceptional
> behavior to match DbC.)

Contract A and contract B describe two different behaviours. If I want
the behaviour of contract B, I must use contract B. I cannot use contract A,
because it (might) do something different than contract B.

The original claim up thread is that all contracts with runnable
pre-conditions that are accepted by a given client can be converted into
another contract with fewer (possibly zero) pre-conditions which will also
be accepted by a client.

The reverse is not nescessarily true.

>
> Afterall, the exception was caused by something
> that the client did (s=NULL), and not as a result
> of something inside the supplier's code. (Do we
> agree in this point?)

No, I'm not sure that we are in agreement. When you talk about "cause",
it can get philosophical too:

A: "Why was this exception thrown?"
B: "Because there's a throw clause in the supplier's code."
A: "Why is there a throw clause in the supplier's code?"
B: "So that the code satisfies the contract given."
A: "Why is the contract written the way it is written?"
B: "Because that's what the client and the supplier agreed upon."
etc.

>
> Again, DbC approach is much simpler and safe:
> any detected false assertion raises an exception.

This sentence does not nescessarily imply that ALL raised exceptions are
caused by a detected false assertion.

- Oliver

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