Re: Exceptions, Go to Hell!
Joshua Maurice <joshuamaurice@gmail.com> wrote:
"Daniel T." <danie...@earthlink.net> wrote:
Joshua Maurice <joshuamaur...@gmail.com> wrote:
"Daniel T." <danie...@earthlink.net> wrote:
"joe" <jc1...@att.net> wrote:
Daniel T. wrote:
As more of a matter of an educated guess, if you want more
maintainable code, then if you have an error condition which is
unlikely to be handled at the caller, and is instead likely to be
handled much farther up the call stack, then use an exception.
Here you are saying the same thing that Stroustrup and I are saying,
but using different words. If the library can solve the problem then
fine; if it can't then the calling code must ensure that the issue
never gets to the library, i.e., it's a precondition for calling the
library that the issue not exist. Now the only question is what
should the library code do if it happens to detect that the
precondition was not met? terminate the app, throw an exception, or
leave the behavior undefined. Clearly, throwing an exception is the
best choice.
Meh. That's an interesting way of putting it. It rubs me the wrong way
to say that operator new has a precondition that sufficient memory be
available. A precondition to me means something which the caller can
check for or code for.
That is a pretty standard conception, but I don't think it is supported
well in the literature. For example:
Meaning of a correctness formula: {P} A {Q}
"Any execution of A, starting in a state where P holds, will
terminate in a state where Q holds." (Meyer)
In the above, the precondition is P, the postcondition is Q and the
action to be performed is A. As Meyer tells us, this is not a
programming construct, it is a mathematical notation, a conceptual
framework within which to discuss the correctness of programming
constructs. If we allow 'operator new' to have as part of its
postcondition "or throws bad_alloc()", then we cannot call such an
action failure. An implementation of 'operator new' that throws
bad_alloc 10% of the time, even if memory is available would be working
correctly if this were the case.
Stroustrup reminds us that "Unfortunately, the assertions we would like
to make are often at a higher level than the programming language allows
us to express conveniently and efficiently." Yes it is difficult, if not
impossible, to check for adequate memory before calling operator new,
but that does not eliminate the assertion as a candidate for a
precondition.
More generally, there are a class of things which can have their
preconditions met, but still fail. You don't like operator new, so how
about network calls? When I send a large chunk of data, it can confirm
at the front that the socket is still open, and every other
precondition possible. However, I can unplug the cord halfway through,
making the call fail. The network code can do nothing about it. That's
a postcondition violation, or you change its post conditions into the
drivel "may work, may not". The only sensible thing to do is return an
error code or throw an exception stating that it cannot fulfill its
post conditions.
I agree with your assessment above. Watering down the postcondition such
that code that does nothing can still be considered correct is not the
way to go. However, as I have shown above, the correctness formula
*requires* that the action must terminate with the postcondition true if
the precondition was met.
Remember, preconditions and postconditions are not just a correctness
criteria, they can also be used to determine who's at fault. If the
precondition is met, but the postcondition is not, then the action
itself is at fault. I think we can both agree that it would be wrong to
lay the blame on the writer of the network code for failing in the
situation you describe. If the precondition is not met, then something
outside the action is at fault, which we can agree is the case here.