On 06/08/2017 11:27 AM, Olivier FAURE wrote:
Contracts are made to preempt memory corruption, and to protect against
*programming* errors; they're not recoverable because breaking a
contract means that from now on the program is in a state that wasn't
anticipated by the programmer.
Which means the only way to handle them gracefully is to cancel what you
were doing and go back to the pre-contract-breaking state, then produce
a big, detailed error message and then exit / remove the thread / etc.
I might get the idea now. The throwing code could be in the middle of
some unsafe operation when it throws the out-of-bounds error. It would
have cleaned up after itself, but it can't because of the (unexpected)
error.
Silly example:
----
void f(ref int* p) @trusted
{
p = cast(int*) 13; /* corrupt stuff or partially initialize
or whatever */
int[] a; auto x = a[0]; /* trigger an out-of-bounds error */
p = new int; /* would have cleaned up */
}
----
Catching the resulting error is @safe when you throw the int* away. So
if f is `pure` and you make sure that the arguments don't survive the
`try` block, you're good, because f supposedly cannot have reached
anything else. This is your proposal, right?
I don't think that's sound. At least, it clashes with another relatively
recent development:
https://dlang.org/phobos/core_memory.html#.pureMalloc
That's a wrapper around C's malloc. C's malloc might set the global
errno, so it's impure. pureMalloc achieves purity by resetting errno to
the value it had before the call.
So a `pure` function may mess with global state, as long as it cleans it
up. But when it's interrupted (e.g. by an out-of-bounds error), it may
leave globals in an invalid state. So you can't assume that a `pure`
function upholds its purity when it throws an error.
In the end, an error indicates that something is wrong, and probably all
guarantees may be compromised.