Should I use exceptions instead of error codes?

Discussion in 'C++' started by mike3, Nov 16, 2007.

  1. mike3

    mike3 Guest

    Hi.
    (crossposted because the program is in C++ and some C++-related
    elements are discussed, hence comp.lang.c++, plus general program
    design questions are asked, hence comp.programming.)

    I'm making this bignum package in C++. I'm wondering though on how to
    handle the errors. Right now most operations routines return error
    codes if they fail -- but some routines they use inside them, or
    overloaded operators, will throw exceptions on failure. For example,
    the C++ standard library routines that get used, for instance to copy
    vectors or pieces of vectors of digits. These may throw on failure.
    Would it be good to then use a consistent system of error handling
    where bignum ops always throw exceptions instead of returning error
    codes, instead of having some failures throw exceptions and other
    failures release error codes (the exceptions would be coming from the
    standard lib. functions for example)? What is the "ideal" plan for a
    bignum package, anyway?
     
    mike3, Nov 16, 2007
    #1
    1. Advertising

  2. mike3

    anon Guest

    mike3 wrote:
    > Hi.
    > (crossposted because the program is in C++ and some C++-related
    > elements are discussed, hence comp.lang.c++, plus general program
    > design questions are asked, hence comp.programming.)
    >
    > I'm making this bignum package in C++. I'm wondering though on how to
    > handle the errors. Right now most operations routines return error
    > codes if they fail -- but some routines they use inside them, or
    > overloaded operators, will throw exceptions on failure. For example,
    > the C++ standard library routines that get used, for instance to copy
    > vectors or pieces of vectors of digits. These may throw on failure.
    > Would it be good to then use a consistent system of error handling
    > where bignum ops always throw exceptions instead of returning error
    > codes, instead of having some failures throw exceptions and other
    > failures release error codes (the exceptions would be coming from the
    > standard lib. functions for example)? What is the "ideal" plan for a
    > bignum package, anyway?


    I like this paper about exception handling:
    http://neil.fraser.name/writing/exception/
     
    anon, Nov 16, 2007
    #2
    1. Advertising

  3. mike3

    Guest

    On Nov 16, 11:14 am, mike3 <> wrote:
    > Hi.
    > (crossposted because the program is in C++ and some C++-related
    > elements are discussed, hence comp.lang.c++, plus general program
    > design questions are asked, hence comp.programming.)
    >
    > I'm making this bignum package in C++. I'm wondering though on how to
    > handle the errors. Right now most operations routines return error
    > codes if they fail -- but some routines they use inside them, or
    > overloaded operators, will throw exceptions on failure. For example,
    > the C++ standard library routines that get used, for instance to copy
    > vectors or pieces of vectors of digits. These may throw on failure.
    > Would it be good to then use a consistent system of error handling
    > where bignum ops always throw exceptions instead of returning error
    > codes, instead of having some failures throw exceptions and other
    > failures release error codes (the exceptions would be coming from the
    > standard lib. functions for example)? What is the "ideal" plan for a
    > bignum package, anyway?


    Personally I prefer exceptions to error codes. Error codes could
    remain undetected, causing an error to propagate.
    Exceptions cannot go undetected: or they can but you have to
    explicitly code that.

    If an undetected error in the package could cause a big mess, then I
    would report the error using an exception.
    I prefer an application crash with a big bang because of an uncaught
    exception than a big mess that acts nicely and goes undetected.

    I also think that an application is easier to read when its functions
    return the intended return value with the "return" statement, instead
    of saving it in some parameter passed by reference.

    You could also implement some macros that report the stack trace
    traveled by the exception (chained exceptions, or http://www.ddj.com/cpp/191100567
    without chaining the exceptions)

    My 3 USD cents (or 2 eurocents)
     
    , Nov 16, 2007
    #3
  4. mike3

    Pete Becker Guest

    On 2007-11-16 05:14:46 -0500, mike3 <> said:

    > Hi.
    > (crossposted because the program is in C++ and some C++-related
    > elements are discussed, hence comp.lang.c++, plus general program
    > design questions are asked, hence comp.programming.)
    >
    > I'm making this bignum package in C++. I'm wondering though on how to
    > handle the errors. Right now most operations routines return error
    > codes if they fail -- but some routines they use inside them, or
    > overloaded operators, will throw exceptions on failure. For example,
    > the C++ standard library routines that get used, for instance to copy
    > vectors or pieces of vectors of digits. These may throw on failure.
    > Would it be good to then use a consistent system of error handling
    > where bignum ops always throw exceptions instead of returning error
    > codes, instead of having some failures throw exceptions and other
    > failures release error codes (the exceptions would be coming from the
    > standard lib. functions for example)? What is the "ideal" plan for a
    > bignum package, anyway?


    You should begin by listing the possible errors. Off the top of my
    head, I only see two: running out of memory, and attempting to divide
    by zero. The first throws an exception, and you can't fix it, so don't
    try. The latter should probably also throw an exception.

    --
    Pete
    Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
    Standard C++ Library Extensions: a Tutorial and Reference
    (www.petebecker.com/tr1book)
     
    Pete Becker, Nov 16, 2007
    #4
  5. mike3

    Joe Greer Guest

    mike3 <> wrote in news:fd846b87-1e40-482e-8318-
    :

    > Hi.
    > (crossposted because the program is in C++ and some C++-related
    > elements are discussed, hence comp.lang.c++, plus general program
    > design questions are asked, hence comp.programming.)
    >
    > I'm making this bignum package in C++. I'm wondering though on how to
    > handle the errors. Right now most operations routines return error
    > codes if they fail -- but some routines they use inside them, or
    > overloaded operators, will throw exceptions on failure. For example,
    > the C++ standard library routines that get used, for instance to copy
    > vectors or pieces of vectors of digits. These may throw on failure.
    > Would it be good to then use a consistent system of error handling
    > where bignum ops always throw exceptions instead of returning error
    > codes, instead of having some failures throw exceptions and other
    > failures release error codes (the exceptions would be coming from the
    > standard lib. functions for example)? What is the "ideal" plan for a
    > bignum package, anyway?


    The rule of thumb that I use is to ask myself if what I want is stack
    unwinding or not. That is, do I expect my immediate caller to be able
    to handle this problem, or is it more likely to be handled at a higher
    level. If I don't expect my immediate caller to be able to handle it,
    then exceptions are the best answer for error handling. If I expect my
    immediate caller to be able to fix it, then error codes is the way to
    go. Sometimes you end up with a sometimes yes, sometimes no sort of
    answer and you then pick your favorite.

    Exceptions require a certain amount of overhead to throw, so if you
    expect to be having the error a lot, then throwing an exception may not
    be your best alternative. Of course, if you expect the error a lot, it
    is also usually the case that the immediate caller can handle the
    problem and move on, so the first guideline catches that, but it is
    still a concern.

    HTH,
    joe
     
    Joe Greer, Nov 16, 2007
    #5
  6. mike3

    mike3 Guest

    On Nov 16, 7:00 am, Joe Greer <> wrote:
    > mike3 <> wrote in news:fd846b87-1e40-482e-8318-
    > :
    >
    >
    >
    >
    >
    > > Hi.
    > > (crossposted because the program is in C++ and some C++-related
    > > elements are discussed, hence comp.lang.c++, plus general program
    > > design questions are asked, hence comp.programming.)

    >
    > > I'm making this bignum package in C++. I'm wondering though on how to
    > > handle the errors. Right now most operations routines return error
    > > codes if they fail -- but some routines they use inside them, or
    > > overloaded operators, will throw exceptions on failure. For example,
    > > the C++ standard library routines that get used, for instance to copy
    > > vectors or pieces of vectors of digits. These may throw on failure.
    > > Would it be good to then use a consistent system of error handling
    > > where bignum ops always throw exceptions instead of returning error
    > > codes, instead of having some failures throw exceptions and other
    > > failures release error codes (the exceptions would be coming from the
    > > standard lib. functions for example)? What is the "ideal" plan for a
    > > bignum package, anyway?

    >
    > The rule of thumb that I use is to ask myself if what I want is stack
    > unwinding or not. That is, do I expect my immediate caller to be able
    > to handle this problem, or is it more likely to be handled at a higher
    > level. If I don't expect my immediate caller to be able to handle it,
    > then exceptions are the best answer for error handling. If I expect my
    > immediate caller to be able to fix it, then error codes is the way to
    > go. Sometimes you end up with a sometimes yes, sometimes no sort of
    > answer and you then pick your favorite.
    >
    > Exceptions require a certain amount of overhead to throw, so if you
    > expect to be having the error a lot, then throwing an exception may not
    > be your best alternative. Of course, if you expect the error a lot, it
    > is also usually the case that the immediate caller can handle the
    > problem and move on, so the first guideline catches that, but it is
    > still a concern.
    >
    > HTH,
    > joe


    And that last part is the thing. See, for the bignum package, there
    are 3 possible types of errors: overflow, out of memory, divide by
    zero.

    The main concern is because the standard library functions (in
    this case, "vector") may throw an exception if they fail, yet the
    bignum routines return error codes for errors that are produced on
    their level, and isn't that mixing two types of error handling in a
    precarious way?

    Also, the overflow and divide-by-zero conditions may occur more
    commonly in this than you might think, at least with certain
    specific types of fractals. For example, consider the iteration
    of z = sin(z) on the complex plane. It may diverge wildly --
    tetrationally,
    to be precise -- and hence hit the ceiling real quick like you
    wouldn't believe. If the "bailout" value (threshold for when the
    number is considered large enough to be considered "diverged"),
    is set high enough, this will max out pretty quick, generating
    an overflow error. Of course once this is caught the iteration
    algorithm should return that the point diverged and halt calculation,
    so for each pixel there may not be a significant performance loss
    even if the overflow is signaled via exception, as the loop does
    not continue.
     
    mike3, Nov 16, 2007
    #6
  7. mike3

    peter koch Guest

    On 16 Nov., 11:14, mike3 <> wrote:
    > Hi.
    > (crossposted because the program is in C++ and some C++-related
    > elements are discussed, hence comp.lang.c++, plus general program
    > design questions are asked, hence comp.programming.)
    >
    > I'm making this bignum package in C++. I'm wondering though on how to
    > handle the errors. Right now most operations routines return error
    > codes if they fail -- but some routines they use inside them, or
    > overloaded operators, will throw exceptions on failure. For example,
    > the C++ standard library routines that get used, for instance to copy
    > vectors or pieces of vectors of digits. These may throw on failure.
    > Would it be good to then use a consistent system of error handling
    > where bignum ops always throw exceptions instead of returning error
    > codes, instead of having some failures throw exceptions and other
    > failures release error codes (the exceptions would be coming from the
    > standard lib. functions for example)? What is the "ideal" plan for a
    > bignum package, anyway?


    For your application, I see no choice but exceptions.
    First, if you want to be able to write your bignum expressions in a
    natural way, e.g. for using operator overloading, an exception is the
    only way to throw an error. operator* can not return an errorcode, and
    you would have to use some ugly hack - e.g. by setting a global error-
    variable.
    The second reason is that a library in general should use exceptions
    as the default error-handling mechanism as it is unlikely that the
    error can always be handled locally. This second point is not an
    universal truth, but the result of my experience in that area.

    /Peter
     
    peter koch, Nov 17, 2007
    #7
  8. mike3

    Pete Becker Guest

    On 2007-11-16 19:23:39 -0500, peter koch <> said:

    >
    > For your application, I see no choice but exceptions.
    > First, if you want to be able to write your bignum expressions in a
    > natural way, e.g. for using operator overloading, an exception is the
    > only way to throw an error. operator* can not return an errorcode, and
    > you would have to use some ugly hack - e.g. by setting a global error-
    > variable.


    Or use the hack that floating-point math typically uses: return a
    special value, not-a-number, that persists through subsequent
    arithmetic operations. Then the user just has to check for it at the
    end.

    --
    Pete
    Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
    Standard C++ Library Extensions: a Tutorial and Reference
    (www.petebecker.com/tr1book)
     
    Pete Becker, Nov 17, 2007
    #8
  9. mike3

    peter koch Guest

    On 17 Nov., 01:27, Pete Becker <> wrote:
    > On 2007-11-16 19:23:39 -0500, peter koch <> said:
    >
    >
    >
    > > For your application, I see no choice but exceptions.
    > > First, if you want to be able to write your bignum expressions in a
    > > natural way, e.g. for using operator overloading, an exception is the
    > > only way to throw an error. operator* can not return an errorcode, and
    > > you would have to use some ugly hack - e.g. by setting a global error-
    > > variable.

    >
    > Or use the hack that floating-point math typically uses: return a
    > special value, not-a-number, that persists through subsequent
    > arithmetic operations. Then the user just has to check for it at the
    > end.
    >
    > --
    > Pete


    Right - that is also a solution, if you call it a hack. I tend to
    agree when we talk about NaN ;-)

    /Peter
     
    peter koch, Nov 17, 2007
    #9
  10. mike3

    Kira Yamato Guest

    On 2007-11-16 19:27:37 -0500, Pete Becker <> said:

    > On 2007-11-16 19:23:39 -0500, peter koch <> said:
    >
    >>
    >> For your application, I see no choice but exceptions.
    >> First, if you want to be able to write your bignum expressions in a
    >> natural way, e.g. for using operator overloading, an exception is the
    >> only way to throw an error. operator* can not return an errorcode, and
    >> you would have to use some ugly hack - e.g. by setting a global error-
    >> variable.

    >
    > Or use the hack that floating-point math typically uses: return a
    > special value, not-a-number, that persists through subsequent
    > arithmetic operations. Then the user just has to check for it at the
    > end.


    This solution sounds elegant, but oh boy is it hard to find where in
    the possibly long and convoluted sequence of calculations did the
    illegal operation originated!

    And why persist in the looong computation once you've reached a NaN already?

    I suggest just throw an exception and end the misery early. Moreover,
    debuggers can be setup to break upon an exception being thrown. Or
    with the proper API's (system dependent), you can dump the call-stack
    at runtime in the exception class constructor.

    --

    -kira
     
    Kira Yamato, Nov 17, 2007
    #10
  11. mike3

    mike3 Guest

    On Nov 16, 5:23 pm, peter koch <> wrote:
    > On 16 Nov., 11:14, mike3 <> wrote:

    <snip>
    > For your application, I see no choice but exceptions.
    > First, if you want to be able to write your bignum expressions in a
    > natural way, e.g. for using operator overloading, an exception is the
    > only way to throw an error. operator* can not return an errorcode, and
    > you would have to use some ugly hack - e.g. by setting a global error-
    > variable.
    > The second reason is that a library in general should use exceptions
    > as the default error-handling mechanism as it is unlikely that the
    > error can always be handled locally. This second point is not an
    > universal truth, but the result of my experience in that area.
    >
    > /Peter


    However, overloaded operators are not the only way of
    accessing the library. The other method is the use of
    member functions, especially special "fast" member
    functions. Those fast functions, since they are not
    overloaded operators, _can_ (and in the present
    implementation, _do_) return error codes. These "fast"
    functions have various optimizations included.

    But now then I have two ways functions can report errors:
    exceptions _and_ error codes (although even error code
    functions may throw exceptions if the standard library
    code they use (if any) fails somehow -- but that's a
    feature of the standard library.). Is this a bad idea
    since then one needs extra handlers for both? However, I
    also have it so error codes returned are objects with member
    functions, one of which can throw the error as an
    exception. This way I can handle the errors in either
    way if one way is more convenient than the other.
     
    mike3, Nov 17, 2007
    #11
  12. mike3

    James Kanze Guest

    On Nov 17, 3:27 am, Kira Yamato <> wrote:
    > On 2007-11-16 19:27:37 -0500, Pete Becker <> said:


    > > On 2007-11-16 19:23:39 -0500, peter koch
    > > <> said:


    > >> For your application, I see no choice but exceptions.
    > >> First, if you want to be able to write your bignum expressions in a
    > >> natural way, e.g. for using operator overloading, an exception is the
    > >> only way to throw an error. operator* can not return an errorcode, and
    > >> you would have to use some ugly hack - e.g. by setting a global error-
    > >> variable.


    > > Or use the hack that floating-point math typically uses: return a
    > > special value, not-a-number, that persists through subsequent
    > > arithmetic operations. Then the user just has to check for it at the
    > > end.


    > This solution sounds elegant, but oh boy is it hard to find where in
    > the possibly long and convoluted sequence of calculations did the
    > illegal operation originated!


    It may not be important. For bad_alloc, I think an exception is
    definitly in order, but in many cases, propagating a result of
    [+-]Inf is sufficient. You don't need to know where the "error"
    occured, only that the results are "infinitly large".

    > And why persist in the looong computation once you've reached
    > a NaN already?


    That's not necessarily the problem. The real problem is that
    handling the special case in all of the operations can be a real
    performance drag, unless (as is the case with IEEE floating
    point) it's done with special hardware (in which case it adds to
    your gate count).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Nov 17, 2007
    #12
  13. mike3

    Pete Becker Guest

    On 2007-11-16 21:27:58 -0500, Kira Yamato <> said:

    > On 2007-11-16 19:27:37 -0500, Pete Becker <> said:
    >
    >> On 2007-11-16 19:23:39 -0500, peter koch <> said:
    >>
    >>>
    >>> For your application, I see no choice but exceptions.
    >>> First, if you want to be able to write your bignum expressions in a
    >>> natural way, e.g. for using operator overloading, an exception is the
    >>> only way to throw an error. operator* can not return an errorcode, and
    >>> you would have to use some ugly hack - e.g. by setting a global error-
    >>> variable.

    >>
    >> Or use the hack that floating-point math typically uses: return a
    >> special value, not-a-number, that persists through subsequent
    >> arithmetic operations. Then the user just has to check for it at the
    >> end.

    >
    > This solution sounds elegant, but oh boy is it hard to find where in
    > the possibly long and convoluted sequence of calculations did the
    > illegal operation originated!


    Well, no, it's not hard when you're debugging. Just install a trap handler.

    >
    > And why persist in the looong computation once you've reached a NaN already?


    Speed. Correct code with correct data doesn't produce NaNs.

    --
    Pete
    Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
    Standard C++ Library Extensions: a Tutorial and Reference
    (www.petebecker.com/tr1book)
     
    Pete Becker, Nov 17, 2007
    #13
  14. mike3

    Kira Yamato Guest

    On 2007-11-17 08:24:46 -0500, Pete Becker <> said:

    > On 2007-11-16 21:27:58 -0500, Kira Yamato <> said:
    >
    >> On 2007-11-16 19:27:37 -0500, Pete Becker <> said:
    >>
    >>> On 2007-11-16 19:23:39 -0500, peter koch <> said:
    >>>
    >>>>
    >>>> For your application, I see no choice but exceptions.
    >>>> First, if you want to be able to write your bignum expressions in a
    >>>> natural way, e.g. for using operator overloading, an exception is the
    >>>> only way to throw an error. operator* can not return an errorcode, and
    >>>> you would have to use some ugly hack - e.g. by setting a global error-
    >>>> variable.
    >>>
    >>> Or use the hack that floating-point math typically uses: return a
    >>> special value, not-a-number, that persists through subsequent
    >>> arithmetic operations. Then the user just has to check for it at the
    >>> end.

    >>
    >> This solution sounds elegant, but oh boy is it hard to find where in
    >> the possibly long and convoluted sequence of calculations did the
    >> illegal operation originated!

    >
    > Well, no, it's not hard when you're debugging. Just install a trap handler.


    Ok. I will buy this.

    >
    >>
    >> And why persist in the looong computation once you've reached a NaN already?

    >
    > Speed. Correct code with correct data doesn't produce NaNs.


    Care to explain how checking for special values (NaN, Inf) for every
    arithematic operations can result in speed up? Wouldn't the code need
    if statements to handle
    NaN + NaN = NaN
    Inf + Inf = Inf
    Inf - Inf = NaN
    Inf * Inf = Inf
    Inf / Inf = NaN
    and so on?

    In fact I will say having special values will slow down computations
    (unless your hardware supports it). In this case, the OP is writing
    software here.

    --

    -kira
     
    Kira Yamato, Nov 17, 2007
    #14
  15. mike3

    Guest

    On Nov 16, 3:14 am, mike3 <> wrote:
    > Hi.
    > (crossposted because the program is in C++ and some C++-related
    > elements are discussed, hence comp.lang.c++, plus general program
    > design questions are asked, hence comp.programming.)
    >
    > I'm making this bignum package in C++. I'm wondering though on how to
    > handle the errors. Right now most operations routines return error
    > codes if they fail -- but some routines they use inside them, or
    > overloaded operators, will throw exceptions on failure. For example,
    > the C++ standard library routines that get used, for instance to copy
    > vectors or pieces of vectors of digits. These may throw on failure.
    > Would it be good to then use a consistent system of error handling
    > where bignum ops always throw exceptions instead of returning error
    > codes, instead of having some failures throw exceptions and other
    > failures release error codes (the exceptions would be coming from the
    > standard lib. functions for example)? What is the "ideal" plan for a
    > bignum package, anyway?


    Why not provide both if that is an option? Another thing to consider
    is where this code is being used. Now, I personally wrote/copied/
    incorporated my own BigInteger class. I used exceptions because I am
    using it in a high-level language that expects to see things like
    exceptions. However, if you are using an older version of C++ or are
    working with low-level routines, error codes can be much better
    suited. If you are writing the code for somebody else, ask them what
    they want. If you are writing it for yourself, ask yourself what
    methodology your prefer.

    People who use exceptions rarely understand the responsibility that
    can go along with them. Exception-safe code is a sought after ideal
    that is rarely realized by novices or even thought of by most
    programmers in general. However, the same thing can apply with error
    codes. Many beginner C programmers rarely even check for errors like
    bad file-reads/opens/writes and continue on with the program until it
    dies unexpectantly. Exceptions at least have the benefit of preventing
    programmers from ignoring potential issues and stop the program where
    something goes wrong.

    Exceptions are becoming faster with each new implementation of C++ and
    they are almost cost-free in Java and C#. So don't let the warnings
    about their inefficiencies scare you away from using them. Remember,
    premature optimization is the root all evil (or was it that irrational
    numbers were the square root of all evil). Modern programming style
    (which is controlled by a bunch of big-headed project consultants and
    authors) says exceptions are the way to go. Be careful about who you
    decide to listen to. I still say it should always depend on your
    environment, including the skillsets of your coworkers, self and tools.
     
    , Nov 17, 2007
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Shane Groff

    Exceptions vs. Error Codes

    Shane Groff, Oct 10, 2004, in forum: C++
    Replies:
    8
    Views:
    691
    Mike Wahler
    Oct 10, 2004
  2. Replies:
    2
    Views:
    2,896
    Malcolm
    Aug 20, 2005
  3. Allen
    Replies:
    1
    Views:
    667
    Mark Rae [MVP]
    Dec 3, 2007
  4. Replies:
    4
    Views:
    83
    Joakim Braun
    Dec 12, 2005
  5. mike3
    Replies:
    135
    Views:
    2,041
    gremnebulin
    Jun 20, 2012
Loading...

Share This Page