On exceptions, errors, and contract violations
Sean Kelly via Digitalmars-d
digitalmars-d at puremagic.com
Fri Oct 3 10:40:41 PDT 2014
I finally realized what's been bugging me about thew program
logic error, airplane vs. server discussion, and rather than have
it lost in the other thread I thought I'd start a new one. The
actual problem driving these discussions is that the vocabulary
we're using to describe error conditions is too limited. We
currently have a binary condition. Either something is a
temporary environmental condition, detected at run-time, which
may disappear simply by retrying the operation, or it is a
programming logic error which always indicates utter,
irrecoverable failure.
Setting aside exceptions for the moment, one thing I've realized
about errors is that in most cases, an API has no idea how
important its proper function is to the application writer. If a
programmer passes out of range arguments to a mathematical
function, his logic may be faulty, but *we have no idea what this
means to him*. The confusion about whether the parameters to a
library constitute user input is ultimately the result of this
exact problem--since we have no idea of the importance of our
library in each application, we cannot dictate how the
application should react to failures within the library.
A contract has preconditions and postconditions to validate
different types of errors. Preconditions validate user input
(caller error), and postconditions validate resulting state
(callee error). If nothing else, proper communication regarding
which type of error occurred is crucial. A precondition error
suggests a logic error in the application, and a postcondition
error suggests a logic error in the function. The function
writer is in the best position to know the implications of a
postcondition failure, but has no idea what the implications of a
precondition failure might be. So it's reasonable to assert that
not only the type of contract error is important to know what to
fix, but also to know how to react to the problem.
Another issue is what the error tells us about the locality of
the failure. A precondition indicates that the failure simply
occurred sometime before the precondition was called, while a
postcondition indicates that the failure occurred within the
processing of the function. Invariant failures might indicate
either, which leads me to think that they are too coarse-grained
to be of much use. In general, I would rather know whether the
data integrity problem was preexisting or whether it occurred as
the result of my function. Simply knowing that it exists at all
is better than nothing, but since we already have the facility
for a more detailed diagnosis, why use invariants?
Without running on too long, I think the proper response to this
issue is to create a third subtype of Throwable to indicate
contract violations, further differentiating between pre and
postcondition failures. So we use Exception to represent
(environmental) errors which may disappear simply from retrying
the operation (and weirdly, out of memory falls into this
category, though @nothrow precludes recategorization), Error to
represent, basically, the things we want to be allowable in
@nothrow code, and ContractFailure (with children:
PreconditionFailure, PostconditionFailure, and InvariantFailure)
to indicate contract violations. This gets them out from under
the Exception umbrella in terms of having them accidentally
discarded, and gives the programmer the facility to handle them
explicitly. I'm not entirely sure how they should operate with
respect to @nothrow, but am leaning towards saying that they
should be allowable just like Error.
The question then arises, if contract failures are valid under
@nothrow, should they derive from Error? I'm inclined to say no,
because Error indicates something different. An Error results as
a natural consequence of code that should be legal everywhere.
Divide by zero, for instance. It isn't practical to outlaw
division in @nothrow code, so a divide by zero error is an Error.
But contract violations are something different and I believe
they deserve their own category.
How does this sound? It's only the beginnings of an idea so far,
but I think it's on the right track towards drawing meaningful
distinctions between error conditions in D.
More information about the Digitalmars-d
mailing list