Assert and the optional Message

Jonathan M Davis jmdavisProg at gmx.com
Fri Mar 9 10:37:38 PST 2012


On Friday, March 09, 2012 09:59:42 H. S. Teoh wrote:
> On Fri, Mar 09, 2012 at 08:56:10AM -0800, Jonathan M Davis wrote:
> > On Friday, March 09, 2012 16:07:10 Timon Gehr wrote:
> > > On 03/09/2012 03:24 PM, Jacob Carlborg wrote:
> [...]
> 
> > > > I still want it to call finally blocks, scope statements, and
> > > > destructors.
> > > 
> > > I have never actually observed that those are not run for assertion
> > > failures.
> > 
> > The current implementation may not skip them, but if so, that might
> > actually be a bug. Errors are not intended to be recoverable, so you
> > can't rely on them hitting finally blocks, scope statements, or
> > destructors. They may very well do so at present. While it's not
> > guaranteed that they will, I'm not sure that it's guaranteed that they
> > _won't_. So, it may or may not be a bug if they do.
> > 
> > It was never intended that AssertError or any other Error be
> > particularly catchable, but it's also true that D is a systems
> > programming language, so it'll let you do stuff which is unsafe, so if
> > you know what you're doing, then there are circumstances where you can
> > get away with (unit testing is one example of where catching
> > AssertErrors might make sense). But you have to know what you're
> > doing, since it's _not_ safe.
> 
> [...]
> 
> This opens up the question of, what's the *recommended* way of writing
> unittests that check for these sorts of stuff?
> 
> For example, I believe in being thorough in unit tests, so I like to use
> them to verify that the complicated in-contract I just wrote actually
> prevents the erroneous calls that I *think* it prevents. But if catching
> AssertError's may leave the program in an undefined state, then that
> pretty much invalidates any further testing past that point (the program
> may appear to work when compiled with -funittest but actually fail in
> release mode).

If you're testing that contracts throw when they're supposed to, you're going 
to have to be very careful. Depending on what code is involved, catching the 
AssertError could have no problems whatsoever. For example

assertThrown!AssertError(func(5));

void func(int i)
in
{
 assert(i == 2);
}
body
{}

wouldn't be a problem at all. There are no destructors, scope statements, or 
finally blocks involved. But something like

assertThrown!AssertError(foo(5));

int foo(int i)
out(result)
{
 assert(result = == 2);
}
body
{
 Bar bar;

 return i;
}

could have issues if Bar has a constructor than needs to run. You just need to 
understand that destructors, scope statements, and finally blocks are not 
guaranteed to be run if an Error is thrown and avoid catching Errors in cases 
where they'd be skipped (or know enough about the state that the program would 
be in if they _were_ skipped to know that it's not going to cause problems).

Personally, I think that checking contracts is overkill, but you can do it if
you're careful.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list