On exceptions, errors, and contract violations

via Digitalmars-d digitalmars-d at puremagic.com
Fri Oct 3 12:46:15 PDT 2014


On Friday, 3 October 2014 at 17:40:43 UTC, Sean Kelly wrote:
> 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.

Yes, I agree. The exceptions are serious hardware instability 
issues. Or serious errors such as a garbage collector going 
bananas with no possibility of ever reclaiming any lost memory. 
Those are not application level concerns. Those are kernel or 
foundational runtime concerns.

I don't want my website to tank just because some library author 
wrote code that is incapable of dealing with 29th of February in 
a date conversion. I don't want the website to tank because a 
validator throws a type related error. I want the validation to 
fail, but not the program. The failure should be local to what 
you are calling into.

The conversion from a local failure to a fatal error can only be 
done by the application in most cases.

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

Preconditions establish what input the postconditions are 
guaranteed to hold for. They don't really validate.

Preconditions say this: if you call me with other values than the 
ones in the precondition you may or may not get what you want, it 
is not my responsibility.

> A precondition error suggests a logic error in the application, 
> and a postcondition error suggests a logic error in the 
> function.

I'd rather say:

1. If you call into a function breaking the precondition, then 
the calling module is responsible for any errors that may occur 
later on. (or rather the contractor that wrote it)

2. If the postcondition fails for input that satisfies the 
precondition then the called module is responsible. (or rather 
the contractor that wrote it)

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

If the modules are isolated then the system architect can define 
which modules are critical and which are not. So he or she can 
decide whether the module should continue, be turned off, logged 
for manual correction at later stage, reset or if the whole 
system should enter some kind of emergency mode.

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

Yes, and maybe even know which contractor should be called to fix 
the problem.

>  But contract violations are something different and I believe 
> they deserve their own category.

The support for contracts in D is not really meaningful IMO. It 
is basically just regular asserts with syntax dressing.

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

I like where you are going, but think about this:

Is infinite recursion a logic error?

It should not be considered to be, because you can solve a 
problem using N strategies concurrently and choose the one that 
returns a valid result first.

Hence logic errors are not fatal errors until the application 
code says so.

It makes a lot of sense to cut down on the amount of code you 
have to write and let runtime errors happen, then catch them and 
swallow them. It makes sense to just swallow errors like typing 
issues if they should not occur for a result you want to use.

You simply turn the "logic error" into a "cannot compute this" 
result if that is suitable for the application. And the 
programming language should not make this hard.


More information about the Digitalmars-d mailing list