When should assert() be used? - c++

In developing a large C++ programming project with many developers, we have run into issues with inappropriate use of assert() in the code which results in poor quality where the assertion does indeed occur and the product crashes.
The question is what are good principles to apply to use assert() appropriately? When is it proper to use an assert() and when is it not? Is there a list of criteria that each assertion should pass in order to be legitimate? How can we encourage proper use of assert()?
As a first crack at this, I would say that assert() should only be used to document a condition that is believed to be impossible to reach and which should be identified as an assert() failure at run time where it ever to arise because programming assumptions are being violated.
Can folks do better than this? What is your experience with assert()?

Use Exceptions for error condition which come from the outside (outside the method or outside the program) like parameter checking and missing/defective external ressources like files or connections or user input.
Use Assertions to indicate an internal defects like programming errors, conditions that shouldn't occur, e.g. class/method invariants and invalid program state.

You should use assert to check all conditions that should never happen:
Preconditions on input parameters
Results of intermediate calculations
Postconditions on object state
But you should include those asserts only in debug builds or when explicitly activated for release (not in builds released to the customers).

I use asserts to check for any unwanted program state:
Function preconditions
Sometimes I insert them in a macro after every API call: glDrawArray(); checkOpenGLError();--checkOpenGLError() will call getGLError() if turned on
Data structure integrity: assert(something == null);
Sometimes GDB lies to me (iOS SDK 3.2). I use asserts to prove it.
Note that "unwanted program state" excludes errors that naturally occur at runtime, such as being unable to open a user-selected file due to permissions or HD failure. In these cases it is not wise to use assertions.

Much code nowadays has a lot of external dependencies and connections. I don't tend to use traditional assertions much these days, I favor exceptions. I don't feel like I can assume "this can never happen" and the checks can safely be removed in a non-debug build.

Related

Why assert macro makes use only for debug build

Why is this a common practice to have assert macro do something useful only in debug configuration? If it exists to test invariants and detect coding bugs, then would not it be easier to go ahead and do the same big boom in production software?
I have some S60 background and there exist __ASSERT_ALWAYS and __ASSERT_DEBUG, where the latter is equivalent to assert.
Asserts are made for stuff that should never happen, i.e. if it does then there is a bug in your code that you need to fix. Releases are builds that are "supposed" to be bug free, and killing application with the assert for the user is as bad as any other faulty behavior.
Checking for assertion costs. You have extra operations that you may not want to exist in the final product. If assertions were always going to work, then people would start using them less "to not kill performance". And believe me, there are a lot of people out there who consider the extra checks a performance kill and would avoid it. These are the same people who actually have to use assert more!
A more important reason is that, assert, if failed, will just abort your program. There is no usefulness in that whatsoever for the end user (except perhaps for security, to avoid running code with unexpected data, but that's arguably better handled by actual error checking). If you want your program to actually terminate with a message or do something useful, you would have to write your own assert. In that case, you can of course choose to keep it in release mode also.
Finally, assertion helps you find bugs, especially hidden bugs, but in the execution of the software, they may actually not happen. Imagine the following code:
struct X
{
// other stuff
int stage;
};
X x;
... do some stuff
assert(x.stage == STAGE_2);
x.stage = STAGE_3; // go to next stage
... do more stuff
In such an example, your logic says x should be in STAGE_2. If it is not, it's a bug. However, if you remove the assert, fix x.stage and move on, there is hope that the bug is not so severe. In such a case, the end-user can actually continue working without noticing this. If you had kept assert in release mode too, you would force the application to exit over a bug that didn't have any visible effect.
In reality, you get updates all the times for your software, in which they claim they have fixed bugs. Some of those, are indeed bugs that assert would have caught. However, you as the end-user didn't have any problem and were actually happy that you weren't interrupted due to those asserts, weren't you?
I think it's a cultural thing. The arguments in favour removing this kind of check in production code go like this:
It makes your code run slower.
It makes the final executable larger.
Your code shouldn't have bugs in once it ships.
It will cause your program to exit suddenly and violently, with possible loss of data.
The arguments against run as follows
You're shipping the exact code that you tested.
Debugging problems reported in the field gets much easier
Regardless of what you'd like to think, the code you ship WILL have bugs
Performance and size effects are typically minimal.
Failing fast may be preferable to attempting to continue when your program is in an undesired state.
Personally, I ship software that's built exactly as it's tested, asserts and all. But, a lot depends on your customer base and how you hope to schedule releases...
This article is worth a read:- http://www.martinfowler.com/ieeeSoftware/failFast.pdf
but what about when you deploy the software to customers? We don’t
want the application to crash just because there’s a typo in a
configuration file. One reaction to this fear is to disable assertions
in the field.
Don’t do that! Remember, an error that occurs at the
customer’s site made it through your testing process. You’ll probably
have trouble reproducing it. These errors are the hardest to find, and
a well-placed assertion explaining the problem could save you days of
effort.
One other thing - in C++, using BOOST_ASSERT you can set it to throw an exception on assertion failure, which makes handling and potentially recovering from assertion failures even more useful. we use this in conjunction with MadExcept so that any assert failures in the field can be easily posted by the user into our bug tracker, with complete call stacks, screenshots, whathaveyou.
assert works unless you explicitly turn it off. There's (usually) no
reason to turn it off, even in "release" builds, and most of the
released code I've delivered has had assert active.
The main reason for turning it off is performance. In this case, you
turn it off very locally, in the function where the performance is
critical, with something like:
#ifdef TURNOFFCRITICALASSERTS
#define NDEBUG
#include <assert.h>
#endif
// Function with critical code here...
#undef NDEBUG
#include <assert.h>
This is the way the C standards committee designed assert to be used.
Generally, you should not define NDEBUG except locally, like this.

Where to put Assertions?

Having assertions for unexpected conditions is considered to be good defensive coding practice. I happen to place assertions whenever i think something unexpected may happen, but that now seems to be an overkill to me.
Additionally, sometimes mild unexpected conditions that don't necessarily lead to crash may even cause failure on customer end.
Is there a hard and fast rule to put assertions?
Thanks.
The main difference between when to use assertions and exceptions:
Use an assertion to catch programming errors. Assertions should never happen if the code has been written correctly.
Use exceptions to catch run-time errors caused by unexpected environment.
If your program reads a script or contents from a file and they do not match the expected format, I consider that is a runtime condition therefore an exception.
You may decide, for debugging purposes, to use an assertion in the place where an exception is thrown simply to be able to work out more easily where it got thrown, although you can use exception macros that insert FILE and LINE into the message to do that too.
Where to put assertions?
What is often overlooked is that an assert can also serve as a documentation aid.
So don't only test for the 'unexpected', also use them to express your assumptions (invariants) at critical points in your code. Like assert(high >= low)
And of course make them conditional, as others have pointed out here.
No there is not... but I would definitely recommend treating assertions differently in test and production.
It is perfectly okay, in a test environment, to produce a core dump. It allows easy inspection of the conditions that triggered the assertion by nicely safe keeping the whole state of the program.
However in a production environment, you never want to crash (except in case of memory corruption...). The user is expecting the system to always respond, there is nothing more irritating that requesting something and never receiving a response. Therefore it is your job to ensure that the user gets the more meaningful response possible, even if it is an error message. The simplest way to achieve this is usually to throw an exception.
Assertions are put when you are very sure that some conditions have to be true before going to the next level of your code. For example when a window handle is invalid or when some varible is not having a valid value.
from the sounds of it, you leave them enabled in release builds. if so, create levels of assertions - those that will be enabled or disabled in certain builds. then just use an assertion level.
this way, you don't need to turn them down, off, or remove them for development and debug builds or beta releases.
i typically disable them in release, but they do consume a ton of written code. i don't think it's bad - it serves as documentation and enforces the interface to be used as intended. i think it's good to have what many devs may consider too many assertions, but there really aren't too many in the big picture because codebases evolve and this ensures that the programs are always used as intended. therefore, i don't recommend removing them, just disable the non-fatal checks for release builds.
ultimately, there are better approaches than levels (see discussion below and take what you want from others' responses) - but levels are one simple way to introduce the change without affecting existing programs considerably. this would be a good approach for a transition to another error handling scheme, or if you're >98% happy with what you have already.

What is the role of asserts in C++ programs that have unit tests?

I've been adding unit tests to some legacy C++ code, and I've run into many scenarios where an assert inside a function will get tripped during a unit test run. A common idiom that I've run across is functions that take pointer arguments and immediately assert if the argument is NULL.
I could easily get around this by disabling asserts when I'm unit testing. But I'm starting to wonder if unit tests are supposed to alleviate the need for runtime asserts. Is this a correct assessment? Are unit tests supposed to replace runtime asserts by happening sooner in the pipeline (ie: the error is caught in a failing test instead of when the program is running).
On the other hand, I don't like adding soft fails to code (e.g. if (param == NULL) return false;). A runtime assert at least makes it easier to debug a problem in case a unit test missed a bug.
A runtime assert at least makes it easier to debug a problem in case a unit test missed a bug.
This is a pretty fundamental point. Unit tests are not meant to replace assertions (which IMHO are a standard part of producing good quality code), they're meant to complement them.
Secondly, lets say you have a function Foo which asserts that it's parameters are valid.
In your unit test for Foo you can make sure you only supply valid parameters, so you think you're alright.
6 months down the track some other developer is going to call Foo from some new piece of code (which may or may not have unit tests), and at that point you'll be very grateful you put those asserts in there.
If your unit test code is correct, then the assert is a bug that the unit test has uncovered.
But it is far more likely that your unit test code is violating the constraints of the units it tests - your unit test code is buggy!
Commentators have raised the point that:
Consider a unit test that validates the function handles invalid input properly.
The assert is the programmer's way of handling invalid input, by aborting the program. By aborting, the program is functioning properly.
Asserts are only in the debug builds (they are not compiled if the NDEBUG macro is defined) and it's important to test that the program does something sensible in release builds. Consider running your invalid parameters unit-test on release builds.
If you want both worlds - checking asserts fire in debug builds - then you want your in-thread unit test harness to capture these asserts. You can do this by providing your own assert.h rather than using the system one; a macro (you'd want the __LINE__ and __FILE__ and ##expr) would call a function you wrote, which can throw a custom AssertionFailed when run in a unit test harness. This obviously does not capture asserts compiled into other binaries you link against but did not compile from source with your custom asserter. (I'd recommend this over providing your own abort(), but that's another approach you might consider to achieve the same end.)
Assertions catch when your code is being used incorrectly (violating its constraints or preconditions - using a library without initialization, passing NULL to a function that won't accept it, etc.).
Unit tests verify that your code does the right thing as long as it's being used correctly.
Assertions also catch when your code has entered a state which you believed to be impossible (which, since it is believed to be impossible, can't be unit tested).
Interestingly, at least one C++ unit testing framework (Google Test) supports death tests, which are unit tests that verify that your assertions work properly (so that you can know your assertions are doing their job of catching invalid program states).
IMO asserts and unit tests are fairly independent concepts. Neither of them can replace the other.
Asserts are meant to ensure that certain conditions / invariants are always valid during the lifetime of the program. Or to be more precise, to ensure that if such a condition gets broken, we get to know about it ASAP, as close to the root cause of the problem as possible.
Unit tests are meant to ensure that certain parts of the code work properly in isolation from the rest of the program.
You can't ensure by unit testing a class that its environment is always going to fulfill its part of the contract under real life circumstances. More so as said environment includes future developers who might not have a clue about the interface contract governing the usage of this class (be it implicit or carefully documented). And also a host of other software and hardware components, which may change and/or get broken anytime, in a manner uncontrollable by the developers of this specific program.
Usually, you should not be able to trip asserts as they are supposed to catch "impossible situations." If an assert fires, that should indicate a bug.
One exception to this rule is that many developers use asserts to verify that arguments are valid. This is okay provided there is also a backup for builds without asserts:
assert(arg != 0);
if (arg != 0)
throw std::runtime_error();
This way, if a bad argument only happens under specific conditions (i.e. out in the field), it will still be caught.
If you code this way, you can turn off asserts and write negative tests to make sure bad arguments are caught.
Two possibilities here:
1) The behaviour of the function is defined (by its own interface explicitly, or by general rules for the project) when the input is null. The unit test therefore needs to test this behaviour. So you need a handler to run a process that runs the test case, and the handler validates that the code tripped the assertion and aborted, or you need to mock assert somehow.
2) The behaviour of the function is not defined when the input is null. The unit test therefore needs to not pass in null - a test is a client of the code too. You can't test something if there's nothing in particular that it's supposed to do.
There is no third option, "the function has undefined behaviour when passed a null input, but the tests pass in null anyway, just in case something interesting happens". So I don't see how, "I could easily get around this by disabling asserts when I'm unit testing" helps at all. Surely the unit tests will cause the function under test to dereference a null pointer, which isn't any better than tripping an assert. The whole reason the asserts are there is to stop something even worse from happening.
In your case, perhaps (1) applies in DEBUG builds, and (2) applies in NDEBUG builds. So perhaps you could run the null-input tests only on debug builds, and skip them when testing the release build.
I only use asserts to check for things that "can never happen". If an assert fires, then a programming mistake has been made somewhere.
Let's say a method takes the name of an input file, and a unit test feeds it the name of a non-existent file to see if a "file not found" exception is thrown. That's not something that "can never happen". It is possible to not find a file at runtime. I would not use an assert in the method to verify that the file was found.
However, the string length of the file name argument must never be negative. If it is, then there is a bug somewhere. So, I might use an assert to say "this length can never be negative". (It's just an artificial example.)
In the case of your question, if the function asserts != NULL, either the unit test is wrong and should not be sending in NULL, because this will never happen, or, the unit test is valid and NULL might possibly be sent in, and the function is wrong and should not be asserting != NULL and must instead handle that condition.
Personally I don't tend to use asserts as, as you've discovered, they often don't play nicely with unit tests. I tend to prefer throwing exceptions in situations where others would often use asserts. These checks, and the exceptions that are thrown on failure, are present in both debug and release builds and I find that they often catch things that 'can't possibly happen' even in release builds (which asserts often don't as they're often compiled out). I find it works better for me and means that I can write unit tests that expect the exception to be thrown on invalid input rather than expecting an assertion to fire.
Lots of people don't agree, see 1, 2, etc but I don't care. Avoiding asserts and using exceptions instead works well for me and helps me to produce robust code for clients...
First, for a unit test to hit an assert (or an ASSERT or _ASSERT or _ASSERTE on Windows builds), the unit test would need to run the code under test with the debug build.
I guess this can easily happen on a developer's machine. For our nightly builds, we only run the unit tests in the release configuration, so there's no worries about asserts there.
Second, one can take the normative approach with asserts --
Asserts are meant to ensure that certain conditions / invariants are
always valid during the lifetime of the program. Or to be more
precise, to ensure that if such a condition gets broken, we get to
know about it ASAP, as close to the root cause of the problem as
possible.
In this case, no unit test should raise an assertion, because calling the code in a way that an assertion is raised should not be possible.
or one can take the "pragmatic" approach with assertions:
Let developers sprinkle ASSERT all over the place for "don't do this" and "not implemented" scenarios. (And we can argue all day whether that's wrong™ or right™, but that won't get the features delivered.)
If you take the pragmatic approach, then a unit test hitting an assertion means the unit test called the code in a way that is not quite supported by the code. It just may mean that the code "does nothing" in a release build or it may mean that the code crashes in a release build or it may mean that the code does "something interesting".
Here's the options that I have been known to use:
If the assert is accompanied by an additional check to make the call "harmless", make the unit test test for the assertion (in debug) and for the "harmless" condition in release.
For crashes or "something interesting", either there's no unit test that makes sense, or you can make a "debug only" unit test that tests that you really get an assertion (though I'm not so sure that's helpful).
1-
Assert is a good way to clarify invariants (loop invariants) during development of algorithms. It can be useful for "readability" as well as debugging. The language Eiffel by Bertrand Meyer has a keyword invariant. In other languages, assert can be used for this purpose.
2-
Assert can also be used in other circumstances as an intermediate solution during development, and removed gradually while the code is being completed. That is, as TODO items. Some of the asserts (those not in item #1 above) need to be replaced by exception handling, etc. It is much easier to spot them if all such checks are shown as asserts.
3-
I sometimes use it to clarify the type of inputs in languages that don't have type checking system (Python and JavaScript), in certain contexts (e.g. when developing new algorithms). Not sure if it is a recommended practice. Like item #1, it is about increasing the readability of program.

Are assertions always bad? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I used to work for a company where some of the lead architect/developers had mandated on various projects that assertions were not to be used, and they would routinely be removed from code and replaced with exceptions.
I feel they are extremely important in writing correct code. Can anyone suggest how such a mandate could be justified? If so, what's wrong with assertions?
We use a modified version of assert, as per JaredPar's comment, that acts like a contract. This version is compiled into the release code so there is a small size overhead, but disabled unless a diagnostics switch is set, such that performance overhead is minimized. Our assert handler in this instance can be set to disabled, silent mode (e.g. log to file), or noisy mode (e.g. display on screen with abort / ignore, where abort throws an exception).
We used automated regression testing as part of our pre-release testing, and asserts are hugely important here as they allow us to find potential internal errors that cannot be picked up at a GUI level, and may not be initially fatal at a user level. With automation, we can run the tests both with and without diagnostics, with little overhead other than the execution time, so we can also determine if the asserts are having any other side effects.
One thing to be careful of with asserts is side effects. For example, you might see something like assert(MyDatabasesIsOk()), which inadvertently corrects errors in the database. This is a bug, as asserts should never change the state of the running application.
The only really negative thing I can say about assertions is they don't run in retail code. In our team we tend to avoid assertions because of this. Instead we use contracts, which are assertions that run in both retail and debug.
The only time we use assertions now is if one of the following are true.
The assertion code has a noticable performance impact
The particular condition is not fatal
Occasionally there is a piece of code that may or may not be dead. We will add an assertion that essentially says "how did you get here." Not firing does not mean the code is indeed dead but if QA emails me and says "what does this assertion mean," we now have a repro to get to a particular piece of code (it's immediately documented of course).
assertions and exceptions are used for two different things.
Assertions are used for states that should never happen. For example, a signalton pointer should never be null and this error should be picked up during development using an assert. Handling it with an exception is alot more work for nothing.
On the other hand exceptions are used for rare states that could happen in the normal running of an application. For example using fopen and it returns a null pointer. It could happen but most times it will return a valid pointer.
Using assertions is nether wrong nor right but it comes down to personal preference as at the end of the day it is a tool to make programing easier and can be replaced by other tools.
It depends on the criticality of your system: assertions are a failfast strategy, while exceptions can be used when the system can perform some kind of recovery.
For instance, I won't use assertions in a banking application or a telecommunication system : I'd throw an exception, that will be catched upper in the call stack. There, resources can be cleaned, and the next call/transaction can be processed ; only one will be lost.
Assertions are an excellent thing, but not to be confused with parameter/return value checking. You use them in situations that you don't believe will occur, not in situations that you expect could occur.
My favourite place to use them is in code blocks that really shouldn't be reached - such as a default case in switch-statement over an enum that has a case for every possible enum value.
It's relatively common that you might extend the enum with new values, but don't update all switch-statements involving the enum, you'll want to know that as soon as possible. Failing hard and fast is the best you can wish for in such circumstances.
Granted, in those places you usually want something that breaks in production builds as well. But the principle of abort()ing under such conditions is highly recommended. A good stack trace in the debugger gives you the information to fix your bug faster than guessing around.
Is it true that an assertion exists in the debug build, but not in the release build?
If you want to verify/assert something, don't you want to do that in the release build as well as in the debug build?
The only guess is that because an exception is often non-fatal that it makes for a codebase that does not die in some odd state. The counter-point is that the fatality of an assertions points right to where the problem is, thus easy to debug.
Personally I prefer to take the risk of an assertion as I feel that it leads to more predictable code that is easier to debug.
Assertions can be left on simply by not defining NDEBUG, so that's not really an issue.
The real problem is that assertions call abort(), which instantly stops the program. This can cause problems if there is critical cleanup your program must do before it quits. Exceptions have the advantage that destructors are properly called, even if the exception is never caught.
As a result, in a case where cleanup really matters, exceptions are more appropriate. Otherwise, assertions are just fine.
We use assertions to document assumptions.
We ensure in code review that no application logic is performed in the asserts, so it is quite safe to turn them off just shortly before release.
One reason to veto assert() is that it's possible to write code that works correctly when NDEBUG is defined, but fails when NDEBUG is not defined. Or vice versa.
It's a trap that good programmers shouldn't fall into very often, but sometimes the causes can be very subtle. For example, the code in the assert() might nudge memory assignments or code positions in the executable such that a segmentation fault that would happen, does not (or vice versa).
Depending on the skill level of your team, it can be a good idea to steer them away from risky areas.
Note, throwing an exception in a destructor is undefined behaviour.

When should assertions stay in production code? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
There's a discussion going on over at comp.lang.c++.moderated about whether or not assertions, which in C++ only exist in debug builds by default, should be kept in production code or not.
Obviously, each project is unique, so my question here is not so much whether assertions should be kept, but in which cases this is recommendable/not a good idea.
By assertion, I mean:
A run-time check that tests a condition which, when false, reveals a bug in the software.
A mechanism by which the program is halted (maybe after really minimal clean-up work).
I'm not necessarily talking about C or C++.
My own opinion is that if you're the programmer, but don't own the data (which is the case with most commercial desktop applications), you should keep them on, because a failing asssertion shows a bug, and you should not go on with a bug, with the risk of corrupting the user's data. This forces you to test strongly before you ship, and makes bugs more visible, thus easier to spot and fix.
What's your opinion/experience?
See related question here
Responses and Updates
An assertion is error, pure and simple and therefore should be handled like one.
Since an error should be handled in release mode then you don't really need assertions.
That's why I prefer the word "bug" when talking about assertions. It makes things much clearer. To me, the word "error" is too vague. A missing file is an error, not a bug, and the program should deal with it. Trying to dereference a null pointer is a bug, and the program should acknowledge that something smells like bad cheese.
Hence, you should test the pointer with an assertion, but the presence of the file with normal error-handling code.
Slight off-topic, but an important point in the discussion.
As a heads-up, if your assertions break into the debugger when they fail, why not. But there are plenty of reasons a file could not exist that are completely outside of the control of your code: read/write rights, disk full, USB device unplugged, etc. Since you don't have control over it, I feel assertions are not the right way to deal with that.
Yes, I have Code Complete, and must say I strongly disagree with that particular advice.
Say your custom memory allocator screws up, and zeroes a chunk of memory that is still used by some other object. I happens to zero a pointer that this object dereferences regularly, and one of the invariants is that this pointer is never null, and you have a couple of assertions to make sure it stays that way. What do you do if the pointer suddenly is null. You just if() around it, hoping that it works?
Remember, we're talking about product code here, so there's no breaking into the debugger and inspecting the local state. This is a real bug on the user's machine.
Assertions are comments that do not become outdated. They document which theoretical states are intended, and which states should not occur. If code is changed so states allowed change, the developer is soon informed and needs to update the assertion.
Allow me to quote Steve McConnell's Code Complete. The section on Assertions is 8.2.
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.
However, later in the same section, this advice is given:
For highly robust code, assert and then handle the error anyway.
I think that as long as performance is not an issue, leave the assertion in, but rather than display a message, have it write to a log file. I think that advice is also in Code Complete, but I'm not finding it right now.
Leave assertions turned on in production code, unless you have measured that the program runs significantly faster with them turned off.
if it's not worth measuring to prove it's more efficient, then it's not worth sacrificing clarity for a performance gamble." - Steve McConnell 1993
http://c2.com/cgi/wiki?ShipWithAssertionsOn
If you're even thinking of leaving assertions on in production, you're probably thinking about them wrong. The whole point of assertions is that you can turn them off in production, because they are not a part of your solution. They are a development tool, used to verify that your assumptions are correct. But the time you go into production, you should already have confidence in your assumptions.
That said, there is one case where I will turn assertions on in production: If we encounter a reproducible bug in production that we're having a hard time reproducing in a test environment, it may be helpful to reproduce the bug with assertions turned on in production, to see if they provide useful information.
A more interesting question is this: In your testing phase, when do you turn assertions off?
Assertions should never stay in production code. If a particular assertion seems like it might be useful in production code, then it should not be an assertion; it should be a run time error check, i.e. something coded like this: if( condition != expected ) throw exception.
The term 'assertion' has come to mean "a development-time-only check which will not be performed on the field."
If you start thinking that assertions might make it to the field then you will inevitably also start making other dangerous thoughts, like wondering whether any given assertion is really worth making. There is no assertion which is not worth making. You should never be asking yourself "should I assert this or not?" You should only be asking yourself "Is there anything I forgot to assert?"
Unless profiling shows that the assertions are causing performance problems, I say they should stay in the production release as well.
However, I think this also requires that you handle assertion failures somewhat gracefully. For example, they should result in a general type of dialog with the option of (automatically) reporting the issue to the developers, and not just quit or crash the program. Also, you should be careful not to use assertions for conditions that you actually do allow, but possibly don't like or consider unwanted. Those conditions should be handled by other parts of the code.
In my C++ I define REQUIRE(x) which is like assert(x) except that it throws an exception if the assertion fails in a release build.
Since a failed assertion indicates a bug, it should be treated seriously even in a Release build. When my code's performance matters, I will often use REQUIRE() for higher-level code and assert() for lower-level code that must run fast. I also use REQUIRE instead of assert if the failure condition may be caused by data passed in from code written by a third party, or by file corruption (optimally I would design the code specifically to be well behaved in case of file corruption, but we don't always have time to do that.)
They say you shouldn't show those assert messages to end-users because they won't understand them. So? End users may send you an email with a screen shot or some text of the error message, which helps you debug. If the user simply says "it crashed", you have no ability to fix it. It would be better to send the assertion-failure messages to yourself automatically, but that only works if (1) the software runs on a server you control/monitor or (2) the user has internet access and you can get their permission to send a bug report.
If you want to keep them replace them with error handling. Nothing worse than a program just disappearing. I see nothing wrong with treating certain errors as serious bugs, but they should be directed to a section of your program that is equipped to deal with them by collecting data, logging it, and informing the user that your app has had some unwanted condition and is exiting.
Provided they are handled just as any other error, I don't see a problem with it. Do bear in mind though that failed assertions in C, as with other languages, will just exit the program, and this isn't usually sufficient for production systems.
There are some exceptions - PHP, for instance, allows you to create a custom handler for assertion failures so that you can display custom errors, do detailed logging, etc. instead of just exiting.
Our database server software contains both production and debug assertions. Debug assertions are just that -- they are removed in production code. Production assertions only happen if (a) some condition exists that should never exist and (b) it is not possible to reliably recover from this condition. A production assertion indicates that a bug in the software has been encountered or some kind of data corruption has occurred.
Since this is a database system and we are storing potentially enterprise-critical data, we do whatever we can to avoid corrupted data. If a condition exists that may cause us to store incorrect data, we immediately assert, rollback all transactions, and stop the server.
Having said that, we also try to avoid production assertions in performance-critical routines.
Suppose a piece of code is in production, and it hits an assertion that would normally be triggered. The assertion has found a bug! Except it hasn't, because the assertion is turned off.
So what happens now? Either the program will (1) crash in an uninformative way at a point further removed from the source of the problem, or (2) run merrily to completion, likely giving the wrong result.
Neither scenario is inviting. Leave assertions active even in production.
I see asserts as in-line unit tests. Useful for a quick test while developing, but ultimately those assertions should be refactored out to be tested externally in unit tests.
I find it best to handle all errors that are in scope, and use assertions for assumptions that we're asserting ARE true.
i.e., if your program is opening/reading/closing a file, then not being able to open the file is in scope -- it's a real possibility, which would be negligent to ignore, in other words. So, that should have error-checking code associated with it.
However, let's say your fopen() is documented as always returning a valid, open file handle. You open the file, and pass it to your readfile() function.
That readfile function, in this context, and probably according to its design specification, can pretty much assume it's going to get a valid file ptr. So, it would be wasteful to add error-handling code for the negative case, in such a simple program. However, it should at least document the assumption, somehow -- ensure somehow --- that this is actually the case, before continuing its execution. It should not ACTUALLY assume that will always be valid, in case it's called incorrectly, or it's copy/pasted into some other program, for example.
So, readfile() { assert(fptr != NULL); .. } is appropriate in this case, whilst full-blown error handling is not (ignoring the fact that actually reading the file would require some error handling system anyway).
And yes, those assertions should stay in production code, unless its absolutely necessary to disable them. Even then, you should probably disable them only within performance-critical sections.
I rarely use assertions for anything other that compile time type checking. I would use an exception instead of an assertion just because most languages are built to handle them.
I offer an example
file = create-some-file();
_throwExceptionIf( file.exists() == false, "FILE DOES NOT EXIST");
against
file = create-some-file();
ASSERT(file.exists());
How would the application handle the assertion? I prefer the old try catch method of dealing with fatal errors.
Most of the time, when i use assertion in java (the assert keyword) I automatically add some production codes after. According to the case, it can be a logging message, an exception... or nothing.
According to me, all your assertions are critical in dev release, not in production relase. Some of them must be kept, other must be discarded.
ASSERTIONS are not errors and should not be handled as errors. When an assertion is thrown, this means that there is a bug in your code or alternatively in the code calling your code.
There are a few points to avoid enabling assertions in production code:
1. You don't want your end user to see a message like "ASSERTION failed MyPrivateClass.cpp line 147. The end user is NOT you QA engineer.
2. ASSERTION might influence performance
However, there is one strong reason to leave assertions:
ASSERTION might influence performance and timing, and sadly this sometimes matter (especially in embedded systems).
I tend to vote for leaving the assertion on in production code but making sure that these assertions print outs are not exposed to end user.
~Yitzik
An assertion is error, pure and simple and therefore should be handled like one.
Since an error should be handled in release mode then you don't really need assertions.
The main benefit I see for assertions is a conditional break - they are much easier to setup than drilling through VC's windows to setup something that takes 1 line of code.