Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Exceptions or return codes?

Programming

Exceptions or return codes?

by  PerFnurt  Posted    (Edited  )
Question: What should one use: Exceptions or return codes?
The short answer:It depends on the context.
The long answer:
The word "exception" suggests it should be used when something exceptional (as in out of the ordinary) has happened.

Something may "fail" in a normal flow, and an error code may be quite valid in that context.

Consider this trivial function:

Code:
int divide(int a, int b);

It shall divide a with b (anyone surprised?). The first question that comes to mind is
"How to deal with a b==0 situation?".

1. Exception
Way of thinking: "b is not supposed to be 0, but it may happen"

If the function prototype for some reason can't be changed, exception is the only way to deal with division by zero.
It also keeps the function's interface quite generic and intuitive (divide reuturns what you could expect from a
function called divide).


Code:
int divide(int a, int b)
{
    if (b==0) throw DivisionByZeroError
    return a/b;
}

The caller must the be prepared to catch it on some level, doesn't have to be (but can be) immediately at the calling level; it can
be high up in the call stack.

2. Bug
Way of thinking: "b shall never be 0, it should not even be possible to set b to 0"

If it never ever is supposed to be 0, the GUI may be responsible for not allowing user to enter 0, then put a
simple contract/assertion on it.

Code:
int divide(int a, int b)
{
    ASSERT(b!=0);
    return a/b;
}


3. Error code
Way of thinking: "b may very well be 0, but division will fail"

Assume we may change the prototype. Then it could be something like:

Code:
typedef std::pair<bool,int> DivideResult; 
// Division ok    : the bool == true and the int == a/b
// Division failed: the bool == false and the int == 0.

DivideResult divide(int a, int b)
{
    if (b==0)
        return DivideResult(false,0)
    else
        return DivideResult(true, a/b);
}

The calling code must then check the error code before proceeding:
Code:
{
    ...
    DivideResult r = divide(foo,bar);
    if (r.first)
    {
        // Division ok
         result = r.second;
    }
    else
    {
        // Division failed
        ...
    }
}

This may be apropriate if there for example is no other validation of user input. If there's no stopping the user from entering 0, it is something that can happen in the "normal" flow of execution.
The big drawback is that you always have to make special arrangements. You can't do a simple
Code:
if (divide(a,b)+divide(c,d) == 42)  { .... }
as you can when using exceptions (imagine the code you'd have to produre). That is the nice thing with exceptions: You deal with the errors somewhere else, while you "down" in the code just assume everything is alright (if something went wrong you just wouldn't be there).

To get the best from both worlds:
Code:
int divide(int a, int b)
{
    if (b==0) throw DivisionByZeroError
    return a/b;
}

DivideResult attemptDivide(int a, int b)
{
    try
    {
        return DivideResult(true, divide(a,b));
    }
    catch (DivisionByZeroError&)
    {
        return DivideResult(false, 0);
    }
}

Note the semantic difference between "divide" and "attemptDivide".

Conclusion:Based on the context, exceptions, return codes, or assertion/contracts may be the proper thing. It depends on what the code is supposed to do - and even more on how you'd like to use it.
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top