Why should I use asserts?

后端 未结 19 1901
遇见更好的自我
遇见更好的自我 2020-12-12 13:47

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, helm

相关标签:
19条回答
  • 2020-12-12 14:09

    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.

    0 讨论(0)
  • 2020-12-12 14:09

    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.

    0 讨论(0)
  • 2020-12-12 14:12

    Assertion should be used when you do something like this

    a = set()
    a.add('hello')
    assert 'hello' in a
    

    or

    a = 1;
    assert a == 1; // if ram corruption happened and flipped the bit, this is the time to assert
    

    As for exceptions, it's something you programmatically deal with:

    while True:
      try:
        data = open('sample.file').read()
        break // successfully read
      except IOError:
        // disk read fail from time to time.. so retry
        pass
    

    Most of the time it's safer to restart your application when assert happens, because you don't want to deal with impossible cases. But when the expected case happens (expected errors (most of the time from black-box clients, network calls, etc..) the exceptions should be used.

    0 讨论(0)
  • 2020-12-12 14:13

    Asserts should only be used to check conditions during development that are not needed during release.

    Here is a really simple example of how assertion can be used in development.

    A(char* p)
    {
        if(p == NULL)
            throw exception;
    
        B(p);
        C(p);
    
    }
    
    B(char* p)
    {
        assert(p != NULL);
        D(p);
        do stuff;
    }
    
    C(char* p)
    {
        assert(p != NULL);
        D(p);
        do stuff;
    }
    
    D(char* p)
    {
        assert(p != NULL);
        do stuff;
    }
    

    Instead of calling "if(p == NULL) throw exception;" 5 times, you just call it once so you already know it's not NULL upon entering B(), C(), and D(). Otherwise, an assertion will exit in the development phase because you "changed the code!" not because of a "user's input".

    This can make the code run a lot faster in the release version because all you have to do is invoke gcc with "-DNDEBUG" so all of the assertions will not be compiled and all the "unnecessary checks" will be removed in the executable.

    0 讨论(0)
  • 2020-12-12 14:14

    In many project I've worked in, assertions were done with a custom macro that had different behaviour in Debug and Release.

    In Debug, if the condition is false the debugger is started at that point in the code.

    In Release, the error is written to a log file, a warning given to the user, and then the system attempts to save unsaved data. Being in an unknown state, this may fail, but it's worth trying.

    0 讨论(0)
  • 2020-12-12 14:18

    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.

    0 讨论(0)
提交回复
热议问题