Why should I use asserts?
I never got the idea of asserts -- why should you ever use them?
I mean, let's say I were a formula driver and all the asserts were things like security belt, helmet, etc.
The tests (in debug) were all okay, but now we want to do racing (release)! Should we drop all security, because there were no issues while testing?
I will never ever remove them. I think most of the guys that claim that removing something comparable to asserts never profiled their code or the asserts were absolute displaced. I've never seen any real performance advantage especially regarding the 80 / 20 rule.
So, am I missing the point somehow, or could anybody tell me, why I should use asserts? By the way, I'm using unit tests.
First, the performance difference can be huge. In one project our asserts literally caused a 3x slowdown. But they helped us uncover some really pesky bugs.
Which is exactly the point.
Asserts are there to help you catch bugs. And because they are removed in release builds, we can afford to put a lot of them in without worrying about performance. If you're not there to actually act on any failed assertions, they become worthless, so we might as well remove them.
Even catching the error and throwing an exception isn't really a solution. The program logic is flawed, and even if we handle the exception, the program is still broken.
What asserts basically boil down to is "Why bother catching errors you can't handle?"
Some errors must be caught during development. If they slip past testing and into the release build used by a customer, the program is just broken, and no amount of runtime error-checking is going to fix it.
I never got the idea of asserts -- why should you ever use them?
I mean, let's say I were a formula driver and all the asserts were things like security belt, helmet, etc.
Yes, that's a good example of when not to use an assert. These are things that might actually go wrong at runtime, and which need to be checked. Your formula one driver might forget some security precaution, and if he does, we want to halt the whole thing before anyone gets hurt.
But what about the check to see that the engine is installed? Do we need to check that during the race?
Of course not. If we get into the race without an engine, we're screwed, and even if we detect the error, it's too late to do anything about it.
Instead, this is an error that must be caught during development or not at all. If the designers forget to put an engine in their car, they need to detect this error during development. That's an assert. It's relevant to the developers during development, but afterwards, the error must not exist, and if it does, there's nothing we can do.
That's basically the difference. An exception is there to help the user, by handling errors that can be handled.
An assert is there to help you, by alerting you to errors that must never occur in the first place, that must be fixed before the product can be shipped. Errors that do not depend on user input, but on your code doing what it is supposed to do.
The square root of four must never evaluate to three. The error is simply impossible. If it does occur, your program logic is just broken. It doesn't matter how much error handling we wrap around it, it's something that must be caught during development or not at all. If we used exception handling to check for this error and handle it, what is the exception going to do? Tell the user "the program is fundamentally broken. Don't ever use it"?
An email from the developer could have achieved that. Why bother building it into the program code? That's an example of a problem that simply must not occur. If it does, we have to go back and fix the program. No other form of error handling is possible.
But some errors, like being unable to open a file for reading, are possible. Even though it might be a bad thing if it happens, we have to accept that it can happen. So we need to handle it if it does.
Asserts are for catching the errors that can't possibly happen.
Andrew Koenig used to have a good philosophical discussion over the usage of exceptions and assertions in shipping code. In the end, you're guarding against doing wild things when the program is in an irreparably broken state.
I believe, therefore, that when a program discovers something that is irrefutably wrong with its internal state, it is better off terminating at once, rather than giving its caller the opportunity to pretend that nothing is wrong.
If you like, I think that exceptions should be reserved for situations in which it is possible to do something sensible after catching the exception. When you discover a condition that you thought was impossible, it's hard to say much about what might happen afterward.
From Code Complete 2: "Use error-handling for conditions you expect to occur; use assertions for conditions that should never occur."
A commonly-cited example is checking for zero in the denominator before a division.
You're expected to strip the assertions out of production code. They are in there during development to help you catch mistakes.
Unit tests are not a replacement for assertions.
Because they make debugging easier.
The time consuming part of debugging is tracing a problem from the symptom you first notice back to the error in the code. Well written assertions will make the symptom you notice much closer to the actual code problem.
A very simple example would be a bug where you index past the end of an array and cause memory corruption which eventually causes a crash. It can take a long time to trace back from the crash to the offending index operation. However, if you have an assertion next to that index operation that checks your index, then your program will fail right next to the error, so you'll be able to find the problem quickly.
It's a controversial subject. Many people, like myself, do actually prefer to leave them on in production code. If your program is going to go into the weeds anyway, you might as well have the assertion in there so your customer can at least give you the line number and filename (or whatever information or action you configure the assert to do). If you left the assertion out, all the customer could report to you was "it crashed".
This means you probably should not do expensive operations in your assert checks, or at least profile to see if they are going to cause performance problems.