digitalmars.D.learn - Proper Use of Assert and Enforce
- Chris Pons (23/23) Mar 13 2012 I'm new, and trying to incorporate assert and enforce into my
- Jonathan M Davis (99/132) Mar 14 2012 assert has nothing to do with the debug switch. All the debug switch doe...
- Dmitry Olshansky (17/39) Mar 14 2012 A valuable trick, as enforce returns whatever passed to it or throws:
- Spacen Jasset (9/18) Mar 14 2012 Is enforce then a way of generating exceptions in an easier way rather
- Jonathan M Davis (11/15) Mar 14 2012 It is purely a way to make throwing an exception use a syntax similar to...
- Chris Pons (5/24) Mar 14 2012 Thank you for the valuable information! The difference between
- Suliman (4/10) Feb 05 2016 So enforce is just macros on top of:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (11/24) Feb 05 2016 Basically, yes (but of course no macros in D. :) ).
- Minas Mina (16/41) Feb 05 2016 Use assertions when a variable's value should not depend on
- Suliman (2/54) Feb 05 2016 Will asserts stay after compilation in release mode?
- bachmeier (4/5) Feb 05 2016 No. The only assert that remains in release mode is assert(false)
- Marc =?UTF-8?B?U2Now7x0eg==?= (20/35) Feb 05 2016 Or alternatively, you could place the responsibility of ensuring
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
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
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
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.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. ...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!");Seems handy enough, if I understand it's purpose properly. ...
Mar 14 2012
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
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
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);So enforce is just macros on top of: if(!condition) throw new Exception(msg); ?
Feb 05 2016
On 02/05/2016 12:01 AM, Suliman wrote:Basically, yes (but of course no macros in D. :) ). T enforce(E : Throwable = Exception, T)(T value, lazy const(char)[] msg = null, string file = __FILE__, size_t line = __LINE__) if (is(typeof({ if (!value) {} }))) { if (!value) bailOut!E(file, line, msg); return value; } https://github.com/D-Programming-Language/phobos/blob/master/std/exception.d#L360 AliIt 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);So enforce is just macros on top of: if(!condition) throw new Exception(msg); ?
Feb 05 2016
On Wednesday, 14 March 2012 at 05:44:24 UTC, 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!"); 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?Use assertions when a variable's value should not depend on external factors. For example, let's say you want to write a square root function. The input must be >= 0, and because this depends on external factors (e.g. user input), you must check it with `enforce()`. The output of the function must should always be >= 0 as well, but this does not depend on any external factor, so use assert for it (a negative square root is a program bug). auto sqrt(float val) { enfore(val >= 0f); float result = ... assert(result >= 0f); return result; }
Feb 05 2016
On Friday, 5 February 2016 at 08:45:00 UTC, Minas Mina wrote:On Wednesday, 14 March 2012 at 05:44:24 UTC, Chris Pons wrote:Will asserts stay after compilation in release mode?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?Use assertions when a variable's value should not depend on external factors. For example, let's say you want to write a square root function. The input must be >= 0, and because this depends on external factors (e.g. user input), you must check it with `enforce()`. The output of the function must should always be >= 0 as well, but this does not depend on any external factor, so use assert for it (a negative square root is a program bug). auto sqrt(float val) { enfore(val >= 0f); float result = ... assert(result >= 0f); return result; }
Feb 05 2016
On Friday, 5 February 2016 at 09:50:43 UTC, Suliman wrote:Will asserts stay after compilation in release mode?No. The only assert that remains in release mode is assert(false) or assert(0) as a way to identify that you've reached a piece of code that shouldn't be executed.
Feb 05 2016
On Friday, 5 February 2016 at 08:45:00 UTC, Minas Mina wrote:Use assertions when a variable's value should not depend on external factors. For example, let's say you want to write a square root function. The input must be >= 0, and because this depends on external factors (e.g. user input), you must check it with `enforce()`.Or alternatively, you could place the responsibility of ensuring that precondition on the caller, in which case you'd use assert().The output of the function must should always be >= 0 as well, but this does not depend on any external factor, so use assert for it (a negative square root is a program bug). auto sqrt(float val) { enfore(val >= 0f); float result = ... assert(result >= 0f); return result; }For assert()s about values coming from the caller or returned to it, you can use contracts, to make it clear that you're not only checking an internal invariant of your function: auto sqrt(float val) in { assert(val >= 0); } out(result) { if(val == 0) assert(result == 0); assert(result >= 0); } body { // use assert()s in the body only for implementation // details of your algorithm ... }
Feb 05 2016