views:

4257

answers:

18

I've been a professional software engineer for about a year now, having graduated with a CS degree. I've known about assertions for a while in C++ and C, but had no idea they existed in C# and .NET at all until recently.

Our production code contains no asserts whatsoever and my question is this...

Should I begin using Asserts in our production code? And if so, When is its use most appropriate? Would it make more sense to do

Debug.Assert(val != null);

or

if ( val == null )
    throw new exception();
+23  A: 

Put Debug.Assert() everywhere in the code where you want have sanity checks to ensure invariants. When you compile a Release build (i.e., no DEBUG compiler constant), the calls to Debug.Assert() will be removed so they won't affect performance.

You should still throw exceptions before calling Debug.Assert(). The assert just makes sure that everything is as expected while you're still developing.

Mark Cidade
Could you clarify why put in an assertion if you still throw an exception before calling it? Or did I misunderstand your answer?
romkyns
I might have had a reason to say that but if so, I can't remember right now.
Mark Cidade
A: 

I don't know how it is in C# and .NET, but in C will assert() only work if compiled with -DDEBUG - the enduser will never see an assert() if it's compiled without. It's for developer only. I use it really often, it's sometimes easier to track bugs.

unexist
A: 

I would not use them in production code. Throw exceptions, catch and log.

Also need to be careful in asp.net, as an assert can show up on the console and freeze the request(s).

mattlant
+3  A: 

Use asserts to check developer assumptions and exceptions to check environmental assumptions.

fatcat1111
A: 

If you want Asserts in your production code (i.e. Release builds), you can use Trace.Assert instead of Debug.Assert.

This of course adds overhead to your production executable.

Also if your application is running in user-interface mode, the Assertion dialog will be displayed by default, which may be a bit disconcerting for your users.

You can override this behaviour by removing the DefaultTraceListener: look at the documentation for Trace.Listeners in MSDN.

In summary,

  • Use Debug.Assert liberally to help catch bugs in Debug builds.

  • If you use Trace.Assert in user-interface mode, you probably want to remove the DefaultTraceListener to avoid disconcerting users.

  • If the condition you're testing is something your app can't handle, you're probably better off throwing an exception, to ensure execution doesn't continue. Be aware that a user can choose to ignore an assertion.

Joe
+2  A: 

You should use Debug.Assert to test for logical errors in your programs. The complier can only inform you of syntax errors. So you should definetely use Assert statements to test for logical errors. Like say testing a program that sells cars that only BMWs that are blue should get a 15% discount. The complier could tell you nothing about if your program is logically correct in performing this but an assert statement could.

orlando calresian
sorry but exceptions do all the same things, so this answer doesn't address the real question.
romkyns
+1  A: 

Use assertions only in cases where you want the check removed for release builds. Remember, your assertions will not fire if you don't compile in debug mode.

Given your check-for-null example, if this is in an internal-only API, I might use an assertion. If it's in a public API, I would definitely use the explicit check and throw.

Derek Park
+2  A: 

Asserts are used to catch programmer (your) error, not user error. They should be used only when there is no chance a user could cause the assert to fire. If you're writing an API, for example, asserts should not be used to check that an argument is not null in any method an API user could call. But it could be used in a private method not exposed as part of your API to assert that YOUR code never passes a null argument when it isn't supposed to.

I usually favour exceptions over asserts when I'm not sure.

+6  A: 

If I were you I would do:

Debug.Assert(val != null);
if ( val == null )
    throw new exception();
Mark Ingram
How is this solving the problem? With this the debug.assert becomes pointless.
Quibblesome
No it doesn't - it breaks into code at the point just before the exception is thrown. If you have a try / catch somewhere else in your code, you may not even notice the exception!
Mark Ingram
+1 I have had a lot of problems where people would simply try/catch exceptions without doing anything so tracking bug was a problem
Sung Meister
+1 Thanks for the explanation. I was wondering why on earth you'd do this.
Even Mien
I suppose there are cases where you might want to do this, but you should never catch a general exception!
Casebash
A: 

Never put debug code in production

The first one is right when you want to test and fail hard during development when val happens to be null because some initialization failed silently and val should, never, ever be null.

If throwing an exception in case val = null is the expected behavior, then the second choice is the right one.

Johan Buret
Debug.Assert calls are stripped automatically in Release builds. You get that DEBUG pragma for free.
fatcat1111
+1  A: 

You should always use the second approach (throwing exceptions).

Also if you're in production (and have a release-build), it's better to throw an exception (and let the app crash in the worst-case) than working with invalid values and maybe destroy your customer's data (which may cost thousand of dollars).

Thomas Danecker
+10  A: 

From Code Complete

8 Defensive Programming

8.2 Assertions

An assertion is code that’s used during development—usually a routine or macro—that allows a program to check itself as it runs. When an assertion is true, that means everything is operating as expected. When it’s false, that means it has detected an unexpected error in the code. For example, if the system assumes that a customer-information file will never have more than 50,000 records, the program might contain an assertion that the number of records is lessthan or equal to 50,000. As long as the number of records is less than or equal to 50,000, the assertion will be silent. If it encounters more than 50,000 records, however, it will loudly “assert” that there is an error in the program.

Assertions are especially useful in large, complicated programs and in high reliability programs. They enable programmers to more quickly flush out mismatched interface assumptions, errors that creep in when code is modified, and so on.

An assertion usually takes two arguments: a boolean expression that describes the assumption that’s supposed to be true and a message to display if it isn’t.

(…)

Normally, you don’t want users to see assertion messages in production code; assertions are primarily for use during development and maintenance. Assertions are normally compiled into the code at development time and compiled out of the code for production. During development, assertions flush out contradictory assumptions, unexpected conditions, bad values passed to routines, and so on. During production, they are compiled out of the code so that the assertions don’t degrade system performance.

Juan Manuel
A: 

The goal with asserts is to give the programmer immediate notification when an assumption is proven wrong. To best test your code, "crash and crash early".

j0rd4n
+1  A: 

Mostly never in my book. In the vast majority of occasions if you want to check if everything is sane then throw if it isn't.

What I dislike is the fact that it makes a debug build functionally different to a release build. If a debug assert fails but the functionality works in release then how does that make any sense? It's even better when the asserter has long left the company and no-one knows that part of the code. Then you have to kill some of your time exploring the issue to see if it is really a problem or not. If it is a problem then why isn't the person throwing in the first place?

To me this suggests by using Debug.Asserts you're deferring the problem to someone else, deal with the problem yourself. If something is supposed to be the case and it isn't then throw.

I guess there are possibly performance critical scenarios where you want to optimise away your asserts and they're useful there, however I am yet to encounter such a scenario.

Quibblesome
+24  A: 

In Debugging Microsoft .NET 2.0 Applications John Robbins has a big section on assertions. His main points are:

  1. Assert liberally. You can never have too many assertions.
  2. Assertions don't replace exceptions. Exceptions cover the things your code demands; assertions cover the things it assumes.
  3. A well-written assertion can tell you not just what happened and where (like an exception), but why.
  4. An exception message can often be cryptic, requiring you to work backwards through the code to recreate the context that caused the error. An assertion can preserve the program's state at the time the error occurred.
  5. Assertions double as documentation, telling other developers what implied assumptions your code depends on.
  6. The dialog that appears when an assertion fails lets you attach a debugger to the process, so you can poke around the stack as if you had put a breakpoint there.

PS: If you liked Code Complete, I recommend following it up with this book. I bought it to learn about using WinDBG and dump files, but the first half is packed with tips to help avoid bugs in the first place.

Rory MacLeod
+1  A: 

According to the IDesign Standard, you should

Assert every assumption. On average, every fifth line is an assertion.

using System.Diagnostics;

object GetObject()
{...}

object someObject = GetObject();
Debug.Assert(someObject != null);

As a disclaimer I should mention I have not found it practical to implement this IRL. But this is their standard.

alord1689
A: 

Personally I believe that you can usually get away without any Debug.Assert() in your code at all. Instead you should have a unit test written that defines what happens when the situation occurs, and matching code to deal with it in both debug and release.

Since the Debug.Assert goes away in production, what will your program do if it unexpectedly matches the condition? Better to have tests that demonstrate the results.

Jedidja