When programming by contract a function or method first checks whether its preconditions are fulfilled, before starting to work on its responsibilities, right? The two most prominent ways to do these checks are by assert
and by exception
.
- assert fails only in debug mode. To make sure it is crucial to (unit) test all separate contract preconditions to see whether they actually fail.
- exception fails in debug and release mode. This has the benefit that tested debug behavior is identical to release behavior, but it incurs a runtime performance penalty.
Which one do you think is preferable?
See releated question here
There was a huge thread regarding the enabling/disabling of assertions in release builds on comp.lang.c++.moderated, which if you have a few weeks you can see how varied the opinions on this are. :)
Contrary to coppro, I believe that if you are not sure that an assertion can be disabled in a release build, then it should not have been an assert. Assertions are to protect against program invariants being broken. In such a case, as far as the client of your code is concerned there will be one of two possible outcomes:
There is no difference to the user, however, it's possible that the assertions add an unnecessary performance cost in the code that is present in the vast majority of runs where the code doesn't fail.
The answer to the question actually depends much more on who the clients of the API will be. If you are writing a library providing an API, then you need some form of mechanism to notify your customers that they have used the API incorrectly. Unless you supply two versions of the library (one with asserts, one without) then assert is very unlikely the appropriate choice.
Personally, however, I'm not sure that I would go with exceptions for this case either. Exceptions are better suited to where a suitable form of recovery can take place. For example, it may be that you're trying to allocate memory. When you catch a 'std::bad_alloc' exception it might be possible to free up memory and try again.
I tried synthesising several of the other answers here with my own views.
Use assertions for cases where you want to disable it in production, erring toward leaving them in. The only real reason to disable in production, but not in development, is to speed up the program. In most cases, this speed up won't be significant, but sometimes code is time critical or the test is computationally expensive. If code is mission critical, then exceptions may be best despite the slow down.
If there is any real chance of recovery, use an exception as assertions aren't designed to be recovered from. For example, code is rarely designed to recover from programming errors, but it is designed to recover from factors such as network failures or locked files. Errors should not be handled as exceptions simply for being outside the control of the programmer. Rather, the predictability of these errors, compared to coding mistakes, makes them more amiable to recovery.
Re argument that it is easier to debug assertions: The stack trace from a properly named exception is as easy to read as an assertion. Good code should only catch specific types of exceptions, so exceptions should not go unnoticed due to being caught. However, I think Java sometimes forces you to catch all exceptions.