Thread: Exception, assertions AND return codes?

  1. #1
    Supermassive black hole cboard_member's Avatar
    Join Date
    Jul 2005
    Posts
    1,709

    Exception, assertions AND return codes?

    Should I be using them all? Well, I'm only thinking about using exceptions - right now I'm using assert to test for conditions that must be met and are "never" going to be false, leaving return codes for everything else.

    Thoughts? Should I use exceptions? Am I abusing any of this?
    Good class architecture is not like a Swiss Army Knife; it should be more like a well balanced throwing knife.

    - Mike McShaffry

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    It's all depending on what you want to achieve.

    Assert is a good debug tool - it is rarely useful for the end user of the finished application to see that "Assertion ptr != NULL failed on line 666 in c:\myapp\src\evilmodule\evil.c", but it's a great help when a junior developer is running some test-code and managed to make it assert here - you will immediately know what went wrong and where [ok, so you still have to reproduce it and figure out why your ptr variable is NULL when it shouldn't be, but it's better than a crash].

    Return values as error indicators are not that great. But return values as results from functions are GREAT. Compare:
    Code:
    if (isSomething(x)) ...
    with
    Code:
    bool result;
    isSomething(x, result);
    if (result) ...
    But using return values to indicate success or failure of the function itself is not a great plan if you are using exceptions generally.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Supermassive black hole cboard_member's Avatar
    Join Date
    Jul 2005
    Posts
    1,709
    Okies, thankies
    Good class architecture is not like a Swiss Army Knife; it should be more like a well balanced throwing knife.

    - Mike McShaffry

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Asserts are good for conditions that typically means you did something wrong in the code instead of some problem that might happen in runtime.
    Otherwise asserts can be good if there's something you haven't implemented yet, and so if that condition occurs, you can assert to tell you that you need to fix it.
    It's also good at finding invalid program states, such as corrupted data somewhere and such. That's where asserts really shine.

    Both returns and exceptions has their advantages/disadvantages as well.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Use asserts to test things that should always be true in debug mode.
    For internal functions use exceptions to report errors.
    For external functions (i.e. API module boundary functions) translate exceptions to return codes (See: Don't allow exceptions to propagate across module boundaries).

  6. #6
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    To be exact the link says:
    Don't allow exceptions to propagate between two pieces of code unless you control the compiler and compiler options used to build both sides
    And that condition is often met. I would avoid return codes as often as possible because every single code introduces a new execution path together with an own unit test you'll have to design and implement (if you want to avoid introducing even more errors while handling them).

    Use assertions for everything what needs to be fixed in the source code. Use exceptions to react to "uncommon behavior" which can't be handled locally.

    There is also another common level of error handling for software running already at the costumer: Logging. This should of course only be enabled if errors are occurring which can't be reproduced immediately.

  7. #7
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by pheres View Post
    To be exact the link says:
    And that condition is often met. I would avoid return codes as often as possible because every single code introduces a new execution path together with an own unit test you'll have to design and implement (if you want to avoid introducing even more errors while handling them).
    Yes, if it's all internal to your application that's fine. But if you provide some API's that 3rd party code can call, you have to translate the exceptions into return codes. Conversely, if you call a lot of 3rd party API's, it might be useful to write some abstractions for those functions that convert the API return codes into exceptions...

  8. #8
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    Yes that sounds reasonable.

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by pheres View Post
    To be exact the link says:
    And that condition is often met. I would avoid return codes as often as possible because every single code introduces a new execution path together with an own unit test you'll have to design and implement (if you want to avoid introducing even more errors while handling them).
    Exception propagation is itself an execution path. Just using exceptions instead of return codes doesn't relieve you of the task of testing the error paths.

    Use assertions for everything what needs to be fixed in the source code. Use exceptions to react to "uncommon behavior" which can't be handled locally.
    Agreed. Exceptions should be used to report, well, exceptional conditions. Note that this doesn't necessarily mean "error condition." Some error conditions are normal and common. These cases, I think, should be handled by return codes.

    Of course, RAII changes things a little bit, since the only way to report an error condition from a constructor is to throw an exception. But that's okay with me.

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by brewbuck View Post
    Agreed. Exceptions should be used to report, well, exceptional conditions. Note that this doesn't necessarily mean "error condition." Some error conditions are normal and common. These cases, I think, should be handled by return codes.
    Oh, yes, I agree with that. Take for example reading a file, and getting to the end of it will perhaps only give SOME of the requested data, because we didn't know at compile time how big the file is. This is definitely a case of "return the amount of data to the user" [which may be zero bytes if we attempt to read after having reached the end of file].

    On the other hand, if we have a file with fixed size records, and we get "half a record" because the file ends abruptly rather than where having a full record, then that's a broken file, and a suitable thing to make an exception for.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    Quote Originally Posted by brewbuck View Post
    Exception propagation is itself an execution path. Just
    using exceptions instead of return codes doesn't relieve you of the task of
    testing the error paths.
    Lets use an example:

    Code:
    int displayImage()
    {
      int err = loadImage(...);
      if(-5 == err)// not enough memory. can't be handled here
      {
    
         return ...;
      }
      err = blitImage(...);
      if(-28 == err)// init display system failed. cant be handled here
      {
    
          return ...;
      }
      [...]
    }
    
    int main()
    {
      int err = displayImage(...);
      if()// out of mem
      if()//display subsystem failed
    }
    and using execptions

    Code:
    void displayImage()
    {
      loadImage(...); // may throw out of mem
    
      blitImage(...); // may throw init failure
      [...]
    }
    
    int main()
    {
      try
      {
        displayImage(...);
      }
      catch(const out_of_mem&)
      {
         //free some and retry
      }
      catch(const init_failure&)
      {
        // reset something and retry
      }
    
    }
    Ok, the number of execution paths seems to be the same for both variants so my statement about it was wrong. But the first one needs a lot of conditions which are error prone to write. This could be a point for exception handling
    Last edited by pheres; 03-05-2008 at 02:25 AM.

  12. #12
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Ok, the number of execution paths seems to be the same for both variants so my statement about it was wrong. But the first one needs a lot of conditions which are error prone to write. This could be a point for exception handling
    There seems to be another execution path with exceptions: uncaught exception. And that is one advantage of exceptions: you might forget to handle some possible error codes from a function and the program won't tell you. (Of course, you might handle error codes in a switch, add a case for no error and a default case.)

    And another case for exceptions: what if displayImage want's to report true or false if it finished successfully (the return value would mean something different than whether we got to the end of the function)? It would be awkward to return both the boolean and an error code.
    Last edited by anon; 03-05-2008 at 05:43 AM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed