views:

568

answers:

5

I've read plenty of articles (and a couple of other similar questions that were posted on StackOverflow) about how and when to you assertions, and I understood them well. But still, I don't understand what kind of motivation should drive me to use Debug.Assert instead of throwing a plain exception. What I mean is, in .Net the default response to a failed exception is to "stop the world" and display a message box to the user. Though this kind of behavior could be modified, I find it highly annoying and redundant to do that, while I could instead, just throw a suitable exception. This way, I could easily write the error to the application's log just before I throw the exception, and plus, my application doesn't necessarily freeze.

So, why should I, if at all, use Debug.Assert instead of a plain exception? Placing an assertion where it shouldn't be could just cause all kinds of "unwanted behavior", so in my point of view, I really don't gain anything by using an assertion instead of throwing an exception. Do you agree with me, or am I missing something here?

Note: I fully understand what's the difference "in theory" (Debug vs Release, usage patters etc.), but as I see it, I would better of throwing an exception instead of performing an assert. Since if a bug is discovered on a production release, I still would like that the "assertion" would fail (after all, the "overhead" is ridiculously small), so I'll be better off throwing an exception instead.


Edit: The way I see it, if an assert failed, that means that the application entered some kind of corrupted, unexpected state. So why would I want to continue execution? It doesn't matter if the application runs on a debug or release version. The same goes to both

+3  A: 

Assertions are used to check the programmer's understanding of the world. An assertion should fail only if the programmer has done something wrong. For example, never use an assertion to check user input.

Asserts test for conditions that "cannot happen". Exceptions are for conditions that "should not happen but do".

Assertions are useful because at build time (or even run time) you can change their behavior. For example, often in release builds, the asserts aren't even checked, because they introduce unneeded overhead. This is also something to be wary of: your tests may not even be executed.

If you use exceptions instead of asserts, you lose some value:

  1. The code is more verbose, since testing and throwing an exception is at least two lines, while an assert is only one.

  2. Your test and throw code will always run, while asserts can be compiled away.

  3. You lose some communication with other developers, because asserts have a different meaning than product code that checks and throws. If you are really testing a programming assertion, use an assert.

More here: http://nedbatchelder.com/text/assert.html

Ned Batchelder
+3  A: 

EDIT: In response to the edit/note you made in your post: It sounds like using exceptions are the right thing to use over using assertions for the type of things you are trying to accomplish. I think the mental stumbling block you are hitting is that you are considering exceptions and assertions to fulfill the same purpose, and so you are trying to figure out which one would be 'right' to use. While there may be some overlap in how assertions and exceptions can be used, don't confuse that for them being different solutions to the same problem- they aren't. Assertions and Exceptions each have their own purpose, strengths, and weaknesses.

I was going to type up an answer in my own words but this does the concept better justice than I would have:

C# Station: Assertions

The use of assert statements can be an effective way to catch program logic errors at runtime, and yet they are easily filtered out of production code. Once development is complete, the runtime cost of these redundant tests for coding errors can be eliminated simply by defining the preprocessor symbol NDEBUG [which disables all assertions] during compilation. Be sure, however, to remember that code placed in the assert itself will be omitted in the production version.

An assertion is best used to test a condition only when all of the following hold:

* the condition should never be false if the code is correct,
* the condition is not so trivial so as to obviously be always true, and
* the condition is in some sense internal to a body of software.

Assertions should almost never be used to detect situations that arise during software's normal operation. For example, usually assertions should not be used to check for errors in a user's input. It may, however, make sense to use assertions to verify that a caller has already checked a user's input.

Basically, use exceptions for things that need to be caught/dealt with in a production application, use assertions to perform logical checks that will be useful for development but turned off in production.

instanceofTom
I realize all of that. But the thing is, the same statement you marked as bold goes to exceptions as well. So the way I see it, instead of an assertion, I could just throw an exception (since if the "situation that never should occur" does happen on a deployed version, I would still want to be informed of it [plus, the application may enter a corrupted state, so I an exception is suitable, I may not want to continue the normal execution flow)
Assertions should be used on invariants; exceptions should be used when, say, something should not be null, but it will be (like a parameter to a method).
Ed Swangren
I guess it all comes down to how defensively you want to code.
Ned Batchelder
I agree, for what it appears that you need, exceptions are the way to go.You said you would like: Failures detected in production, the ability to log information about errors, and execution flow control, etc. Those three things make me think that what you need is to do is throw around some exceptions.
instanceofTom
A: 

Debug.Assert by default will only work in debug builds, so if you want to catch any sort of bad unexpected behavior in your release builds you'll need to use exceptions or turn the debug constant on in your project properties (which is considered in general not to be a good idea).

Mez
first partial sentence is true, the rest is in general a bad idea: assertions are assumptions and no validation (as stated above), enabling debug in release is really no option.
Marc Wittke
I never said it was a good idea..
Mez
+2  A: 

Another nugget from Code Complete:

"An assertion is a function or macro that complains loudly if an assumption isn't true. Use assertions to document assumptions made in code and to flush out unexpected conditions. ...

"During development, assertions flush out contradictory assumptions, unexpected conditions, bad values passed to routines, and so on."

He goes on to add some guidelines on what should and should not be asserted.

On the other hand, exceptions:

"Use exception handling to draw attention to unexpected cases. Exceptional cases should be handled in a way that makes them obvious during development and recoverable when production code is running."

If you don't have this book you should buy it.

Andrew Cowenhoven
I've read the book, it's excellent. However.. you didn't answer my question :)
You are right I didn't answer it. My answers is no I don't agree with you. Assertions and Exceptions are different animals as covered above and some of the other posted answers here.
Andrew Cowenhoven
+16  A: 

Though I agree that your reasoning is plausible -- that is, if an assertion is violated unexpectedly, it makes sense to halt execution by throwing -- I personally would not use exceptions in the place of assertions. Here's why:

As others have said, assertions should document situations that are impossible, in such a manner that if the allegedly impossible situation comes to pass, the developer is informed. Exceptions, by contrast, provide a control flow mechanism for exceptional, unlikely, or erroneous situations, but not impossible situations. For me, the key difference is this:

  • It should ALWAYS be possible to produce a test case which exercises a given throw statement. If it is not possible to produce such a test case then you have a code path in your program which never executes, and it should be removed as dead code.

  • It should NEVER be possible to produce a test case which causes an assertion to fire. If an assertion fires, either the code is wrong or the assertion is wrong; either way, something needs to change in the code.

That's why I would not replace an assertion with an exception. If the assertion cannot actually fire, then replacing it with an exception means you have an untestable code path in your program. I dislike untestable code paths.

Eric Lippert
Best explanation for the subject I have ever seen. Thanks!
Appu