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.

Reply via email to