assume, assert, enforce, @safe

Timon Gehr via Digitalmars-d digitalmars-d at puremagic.com
Thu Jul 31 14:39:48 PDT 2014


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.



More information about the Digitalmars-d mailing list