On 07/31/2014 11:01 PM, ponce wrote:
Could you expand on what you consider input?  For example, if a
function has an "in" contract that validates input parameters, is
the determination that a parameter is invalid a program bug or
simply invalid input? ...


The assertions in an 'in' contracts are obligations at the call site.

I.e., the code:

void baz(int x){
    assert(x>2);
    // ...
}

is buggy.

The code

void foo(int x)in{ assert(x>2); }body{ assert(x>2); }

is correct.

The code:

void bar(int x){ foo(x); }

is buggy.

The code

void bar(int x){
    enforce(x>2);
    foo(x);
}

is fine.


This also puzzles me. There is the point where the two types of errors
blend to the point of being uncomfortable.

Eg: a program generates files in X format and can also read them with a
X parser. Its X parser will only ever read output generated by itself.
Should input errors in X parser be checked with assert or exceptions?

Use 'assert' for checking things which you expect to be true. But don't be fooled, besides having some loosely checked code documentation, the main reason to write down assertions is that they will occasionally fail and tell you something interesting which you didn't know yet about your program (as it was nicely formulated somewhere else in this thread.) This makes assertions seem a little schizophrenic at times, but after all, checking those assertions, which you _expect_, by definition, to be no-ops anyway, may be too expensive for you and then they can be disabled. I'd check what are the actual performance gains before doing this though. You can also control assertions in a more fine-grained way by guarding them with version statements.

Furthermore, use 'assert' as well in _in_ contracts, and think about them being checked in the context of the caller as an obligation instead of as being checked in your own function.

Use 'enforce' for things which you expect might be false sometimes and that you may want to handle as an exception in this case.

I wouldn't think about 'enforce' as 'not checking program bugs' too hard though. Maybe the bug is in code which does not actually expect the exceptional path to be taken.

The difference between

void foo1(int x)in{ assert(x>2); }body{ ... }

and

void foo2(int x){
    enforce(x>2);
}

Is that 'foo2' reliably throws an exception if the contents of x are not greater than 2; this is part of it's behaviour and would be part of its documentation, while 'foo1' just states in its documentation that it will do a certain thing _provided_ x is greater than 2, and that its behaviour is left unspecified otherwise.


Or that's what I would say anyway if there wasn't talk about turning assertions into assumptions in -release. If nothing changes, always use version(assert) to guard your assert statements unless you want their failures to be undefined behaviour in -release mode.

Reply via email to