Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exceptions vs assert for a scientific computing guy (I am the sole user of my code)?

Exceptions vs assert has been asked here before: Design by contract using assertions or exceptions?, Assertion VS Runtime exception, C++ error-codes vs ASSERTS vs Exceptions choices choices :(, Design by contract using assertions or exceptions?, etc. (*) There are also books, like Herb Sutter's Coding Standards that talk about this. The general consensus seems to be this:

Use assertions for internal errors, in the sense that the user of the module and the developer are one and the same person/team. Use exceptions for everything else. (**)

This rule makes a lot of sense to me, except for one thing. I am a scientist, using C++ for scientific simulations. In my particular context, this means that I am the sole user of most of my code. If I apply this rule, it means I never have to use exceptions? I guess not, for example, there are still I/O errors, or memory allocation issues, where exceptions are still necessary. But apart from those interactions of my program with the "outside world", are there other scenarios where I should be using exceptions?

In my experience, many good programming practices have been very useful to me, in spite of those practices being designed mostly for large complex systems or for large teams, while my programs are mostly small scientific simulations which are written mostly by me alone. Hence this question. What good practices of exception use apply in my context? Or should I use only asserts (and exceptions for I/O, memory allocation, and other interactions with the "outside world")?

(*) I hope that after reading the complete question, you agree that this is not a duplicate. The topic of exceptions vs assert has been dealt with before in general, but, as I try to explain here, I don't feel that any of those questions addresses my particular situation.

(**) I wrote this with my own words, trying to resume what I've read. Feel free to criticize this statement if you feel it does not reflect the majority's consensus.

like image 955
becko Avatar asked Aug 18 '15 14:08

becko


People also ask

Why are exceptions better than assert statements?

Exceptions versus assertions Use assert statements to test for conditions during development that should never be true if all your code is correct. There's no point in handling such an error by using an exception, because the error indicates that something in the code has to be fixed.

What is a potential benefit of using assert over an exception?

You use exceptions for exceptional situations. For example an out of memory situation or a network failure. You use assert to ascertain that a cetain precondition is met. For example a pointer is not NULL or an integer is within a certain range.

Is assertion an exception?

The key differences between exceptions and assertions are: Assertions are intended to be used solely as a means of detecting programming errors, aka bugs. By contrast, an exception can indicate other kinds of error or "exceptional" condition; e.g. invalid user input, missing files, heap full and so on.

Why do we need assert?

Assertions are mainly used to check logically impossible situations. For example, they can be used to check the state a code expects before it starts running or the state after it finishes running. Unlike normal exception/error handling, assertions are generally disabled at run-time.


1 Answers

assert() is a safeguard against programmer mistakes, while exceptions are safeguards against the rest of existence.

Let's explain this with an example:

double divide(double a, double b) {
    return a / b;
}

The obvious problem of this function is that if b == 0, you'll get an error.

Now, let's assume this function is called with arguments which values are decided by you and only you. You can detect the problem by changing the function into this:

double divide(double a, double b) {
    ASSERT(b != 0);
    return a / b;
}

If you have accidentally made a mistake in your code so that b can take a 0 value, you're covered, and can fix the calling code, either by testing explicitely for 0, or to make sure such a condition never occurs in the first place.

As long as this assertion is in place, you will get some level of protection as the developer of the code. It is a contract that makes it easy to see what kind of problem can occur in the function, especially while you are testing your code.

Now, what happens if you have no control over the values that are passed to the function ? The assertion will just disrupt the flow of the program without any protection whatsoever.

The sensible thing to do is this:

double divide(double a, double b) {
    ASSERT(b != 0);
    if (b == 0)
        throw DivideByZeroException();
    return a / b;
}

try {
    result = divide(num, user_val);
} catch (DivideByZeroException & e) {
    display_informative_message_to_user(e);
}

Note that the assertion is still in place because it is the most readable indication of what can go wrong. The addition of the exception, however, allows you to recover more easily from the problem.

It can be argued that such an approach is redundant, but in a release build, the assertions will usually be NOOPs without generated code, so the exception remains the sole protection.
Also, this function is very simple, so the assertion and the exception throw are immediately visible, but with a few dozens of lines of code added, that would not be the case anymore.

Now, when you are developing and likely to do mistakes, the assertion failure will be visible at exactly the line where it occured, while the exception might bubble up into an unrelated try/catch block that would make it harder to pintpoint the problem exactly, especially if the catch block does not log stack traces.

So, if you want to be safe and mitigate the risks of mistakes during development and during normal execution, you can never be too careful, and might want to provide both mechanisms in a complementary way.

like image 50
SirDarius Avatar answered Oct 31 '22 01:10

SirDarius