www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Proper Use of Assert and Enforce

reply "Chris Pons" <cmpons gmail.com> writes:
I'm new, and trying to incorporate assert and enforce into my 
program properly.

My question revolves around, the fact that assert is only 
evaluated when using the debug switch. I read that assert throws 
a more serious exception than enforce does, is this correct?

I'm trying to use enforce in conjunction with several functions 
that initialize major components of the framework i'm using.

However, i'm concerned with the fact that my program might 
continue running, while I personally would like for it to crash, 
if the expressions i'm trying to check fail.

Here is what i'm working on:

	void InitSDL()
	{
		enforce( SDL_Init( SDL_Init_Everything ) > 0, "SDL_Init 
Failed!");

		SDL_WN_SetCaption("Test", null);

		backGround = SDL_SetVideoMode( xResolution, yResolution, 
bitsPerPixel, SDL_HWSURFACE | SDL_DOUBLEBUF);

		enforce( backGround != null, "backGround is null!");

		enforce( TTF_Init() != -1, "TTF_Init failed!" );
	}

Is it proper to use in this manner? I understand that I shouldn't 
put anything important in an assert statement, but is this ok?
Mar 13 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, March 14, 2012 06:44:19 Chris Pons wrote:
 I'm new, and trying to incorporate assert and enforce into my
 program properly.
 
 My question revolves around, the fact that assert is only
 evaluated when using the debug switch.

assert has nothing to do with the debug switch. All the debug switch does is enable debug blocks. e.g. debug { writeln("A debug message."); } If you put an assertion in the debug block, then it'll only be there when you compile with -debug like any other code, but if you put it outside of the debug block, it won't be affected by -debug at all. Rather, assertions are compiled in unless you compile with the -release flag.
 I read that assert throws
 a more serious exception than enforce does, is this correct?

Not exactly. Have you used assertions in other languages? In most languages, an assertion just outright kills your program if it fails. An assertion asserts that a particular condition is true with the idea that if that condition is _not_ true, then there is a bug in your program. As such, you don't want your program to continue if it fails. It's used to verify the integrity of your program. in and out contracts use them as do invariants and unittest blocks. When an assertion fails, an AssertError is thrown, _not_ an Exception. Throwable is the base class of all exception types, and Error and Exception are derived from it. Errors are for conditions which are normally considered fatal and should almost never be caught (for instance, trying to allocate memory when you're out of memory results in an OutOfMemoryError being thrown). Unlike Exceptions, Errors can be thrown from nothrow functions, and the language does not actually guarantee that scope statements, destructors, and finally blocks will be run when an Error is thrown (though the current implementation currently does run them for Errors and there is some discussion of actually guaranteeing that it always will; regardless, catching Errors is almost always a bad idea). Exception and any types derived from Exception cannot be thrown from nothrow functions and _are_ guaranteed to trigger scope statements (aside from scope(success)), destructors, and finally blocks. They are generally meant to be recoverable and catching them is fine. They are generally used to indicate that a function is unable to properly perform its function given the current state of the program but _not_ because of a logic error. Rather, it's because of stuff like bad user input or because a file doesn't exist when it's supposed to, so opening it fails. Exceptions are used for reporting error conditions to your program. It can then either choose to catch them and handle them or let it percolate to the top of the program and kill it. But unlike Errors, it _is_ okay to catch them, and it's intended that they not indicate an unrecoverable error. So, you use an assertion when you want to guarantee something about your program and kill your program when that condition fails (indicating a bug in your program). The checks are then normally compiled out when you compile with -release. So, the idea is to use them to catch bugs during development but to not have them impede the performance of the program when you release it. The only assertions that are always left in are the ones that can be determined to be false at compile time (generally assert(0) and assert(false), though stuff like assert(1 == 0) also qualify, since their result is known at compile time). They're used when you want to guarantee that a particular line is never hit (e.g. when a switch statement is never supposed to hit its default case statement). The compiler actually inserts them at the end of non-void functions so that if the program somehow reaches the end without returning, the program will not try and continue. Exceptions, on the other hand, are _not_ used for bugs in your code, but rather error conditions which occur do to circumstances at runtime which are not controlled by your program (like bad user input). enforce is simply a way to make throwing exceptions look like assertions and save a line of code. So, instead of if(!condition) throw new Exception(msg); you do enforce(condition, msg); And if you want to throw a specific exception type, you do either enforceEx!SpecificException(condition, msg); or enforce(condition, new SpecificException(msg));
 I'm trying to use enforce in conjunction with several functions
 that initialize major components of the framework i'm using.
 
 However, i'm concerned with the fact that my program might
 continue running, while I personally would like for it to crash,
 if the expressions i'm trying to check fail.
 
 Here is what i'm working on:
 
 	void InitSDL()
 	{
 		enforce( SDL_Init( SDL_Init_Everything ) > 0, "SDL_Init
 Failed!");
 
 		SDL_WN_SetCaption("Test", null);
 
 		backGround = SDL_SetVideoMode( xResolution, yResolution,
 bitsPerPixel, SDL_HWSURFACE | SDL_DOUBLEBUF);
 
 		enforce( backGround != null, "backGround is null!");
 
 		enforce( TTF_Init() != -1, "TTF_Init failed!" );
 	}
 
 Is it proper to use in this manner? I understand that I shouldn't
 put anything important in an assert statement, but is this ok?

Shouldn't put anything important in assert statements? I'm afraid that I don't follow. Assertions are compiled out when you compile with -release, so they cannot be used when you want to guarantee that they fail even with - release or if you have code in them that must always run. So, for instance, if the foo function _had_ to be run, doing assert(foo() == expected); would be bad. You'd do immutable result = foo(); assert(result == expected); instead. The same concern does not exist with enforce, however, since it's never compiled out. As for whether assert or enforce should be used, does failure mean a bug in your program or simply that you've hit an error condition. From the looks of your code, it would probably simply be an error condition in this case, since your verifying that some initialization functions succeed. If they fail, it's not a bug in your program but rather that something else (probably outside of your control) went wrong. So, enforce is the correct choice. And if nothing calling initSDL (directly or indirectly) catches the exception, then the exception will kill your program, but it can be caught with a catch block if you choose to. If you want to _guarantee_ that the program dies if any of them fail, then you should probably create a subclass of Error (e.g. SDLInitError) and throw that, in which case, your first enforce would become enforceEx!SDLInitError(SDL_Init(SDL_Init_Everything) > 0, "SDL_Init Failed!"); Hopefully I didn't overload you too thoroughly and this at least gives you a better idea of the difference between assertions and exceptions (and therefore between assert and enforce). Assertions are for verifying the integerity of your program and failure means that your program has a bug, whereas exceptions are for reporting error conditions which do _not_ indicate a bug in your program. - Jonathan M Davis
Mar 14 2012
prev sibling next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 14.03.2012 9:44, Chris Pons wrote:
 I'm new, and trying to incorporate assert and enforce into my program
 properly.

 My question revolves around, the fact that assert is only evaluated when
 using the debug switch. I read that assert throws a more serious
 exception than enforce does, is this correct?

 I'm trying to use enforce in conjunction with several functions that
 initialize major components of the framework i'm using.

 However, i'm concerned with the fact that my program might continue
 running, while I personally would like for it to crash, if the
 expressions i'm trying to check fail.

 Here is what i'm working on:

 void InitSDL()
 {
 enforce( SDL_Init( SDL_Init_Everything ) > 0, "SDL_Init Failed!");

 SDL_WN_SetCaption("Test", null);

 backGround = SDL_SetVideoMode( xResolution, yResolution, bitsPerPixel,
 SDL_HWSURFACE | SDL_DOUBLEBUF);

 enforce( backGround != null, "backGround is null!");

A valuable trick, as enforce returns whatever passed to it or throws: backGround = enforce(SDL_SetVideoMode( xResolution, yResolution, bitsPerPixel, SDL_HWSURFACE | SDL_DOUBLEBUF), "backGround is null!");
 enforce( TTF_Init() != -1, "TTF_Init failed!" );
 }

 Is it proper to use in this manner? I understand that I shouldn't put
 anything important in an assert statement, but is this ok?

To make it real simple: - assert on stuff you know has to be true regardless of circumstances and not dependent on any possible external factors. - enforce on stuff that must be true, but in general can fail like "file not found", etc. and/or depends on proper state of external factors you can't guarantee. Also since assert stay true if program is correct (in common sense) asserts are removed from release binaries. In your case I believe enforce is justified, as capabilities of hardware are not in your direct control and the release version shouldn't segfault in the face of user. -- Dmitry Olshansky
Mar 14 2012
parent Spacen Jasset <spacenjasset yahoo.co.uk> writes:
On 14/03/2012 09:59, Dmitry Olshansky wrote:
...
 To make it real simple:
 - assert on stuff you know has to be true regardless of circumstances
 and not dependent on any possible external factors.
 - enforce on stuff that must be true, but in general can fail like "file
 not found", etc. and/or depends on proper state of external factors you
 can't guarantee.

than using some sort of "if (failure) throw" syntax? In other words, I assume it's a mechanism to help you use exceptions, and not some new semantic. ...
 A valuable trick, as enforce returns whatever passed to it or throws:

 backGround = enforce(SDL_SetVideoMode( xResolution, yResolution,
 bitsPerPixel, SDL_HWSURFACE | SDL_DOUBLEBUF), "backGround is null!");

...
Mar 14 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, March 14, 2012 20:15:16 Spacen Jasset wrote:
 Is enforce then a way of generating exceptions in an easier way rather
 than using some sort of "if (failure) throw" syntax? In other words, I
 assume it's a mechanism to help you use exceptions, and not some new
 semantic.

It is purely a way to make throwing an exception use a syntax similar to assert and save a line of code. if(!condition) throw new Exception(msg); becomes enforce(condition, msg); or enforce(condition, new Exception(msg)); It arguably adds very little, but some people really like it. - Jonathan M Davis
Mar 14 2012
prev sibling parent "Chris Pons" <cmpons gmail.com> writes:
Thank you for the valuable information! The difference between 
assert and enforce is now clearer in my mind.

Also, that's a great trick with enforce.

On Thursday, 15 March 2012 at 01:08:02 UTC, Jonathan M Davis 
wrote:
 On Wednesday, March 14, 2012 20:15:16 Spacen Jasset wrote:
 Is enforce then a way of generating exceptions in an easier 
 way rather
 than using some sort of "if (failure) throw" syntax? In other 
 words, I
 assume it's a mechanism to help you use exceptions, and not 
 some new
 semantic.

It is purely a way to make throwing an exception use a syntax similar to assert and save a line of code. if(!condition) throw new Exception(msg); becomes enforce(condition, msg); or enforce(condition, new Exception(msg)); It arguably adds very little, but some people really like it. - Jonathan M Davis

Mar 14 2012