Error codes vs. exceptions

Discussion in 'C++' started by mike3, May 29, 2012.

  1. mike3

    mike3 Guest

    Hi.

    I've heard about this, and wonder when is it right to use codes, and
    when to use exceptions for reporting errors? I've heard various stuff,
    such as that exceptions should only be used to indicate "exceptional"
    conditions. Yet what does that mean? I've heard that, e.g. a user
    inputting invalid input should not be considered "exceptional", but
    something like running out of memory should be. Does this mean that if
    we have a program, and we have a "parse()" function that parses a
    string input by the user, that this function should return an error
    code on parse failure, instead of throwing an exception? Yet we'll
    probably also come across places where it's good to use an exception,
    in the same program! Which means we get into _mixing error codes and
    exceptions_. And what's the best way to do that?

    Also, how exactly does one go about determining what is and is not
    "exceptional"? Two examples were mentioned of things exceptional and
    non-exceptional, but what about something else, like say in a game,
    where you have a grid representing a game level, and a request for a
    tile of the level is made with a coordinate that is off the map (like
    a 64x64 map and something requests a tile at (100, 100).). Would it be
    OK for the function working on the tile to throw? Or should it give an
    "out of range" error code? And as for that mixing: consider, e.g. C++
    and probably many other languages: a function has a single definite
    return type. Suppose our grid had a function that extracts an
    attribute from a cell. What to do when there's an out-of-bounds
    request? Throw exception? See, what I've currently been doing, and
    it's probably silly, is to use exceptions when our function needs to
    return a value, and error codes when it could otherwise return "void".
    This doesn't seem like a good idea. But what to do? Make every
    function return an error code, using pointers to output variables to
    store output, and only use exceptions for a rare few kinds of "system-
    related" error? Yet one can hardly deny the niceness of being able to
    say "x = f() + <foo>" (inside a "try" block, perhaps) instead of

    if(f(&x) != SUCCESS)
    { // handle error }
    x += foo;

    :)

    Note how we can easily get LONG methods full of repeated code with
    error codes (repeated error handlers to handle similar errors at
    various function calls calling error-code-emitting functions, if one
    wants to be more graceful than simply aborting with an error to the
    next level up (which complicates what error codes a function can
    return, since it can return its own codes in addition to those
    returned by the functions below it, and those may have functions below
    THEM, and so on...).). And who likes duplicated code? eww. This seems
    a disadvantage of error codes.

    Or, and this is what I've been thinking of, use exceptions for every
    error that the user does not have control over, like invalid input
    strings. Would that be OK or excessive use of exceptions? And if we
    are to mix error codes and exceptions, does this mean we should have
    the lists of codes and exceptions correspond + a translator to
    translate between the two?
     
    mike3, May 29, 2012
    #1
    1. Advertising

  2. mike3

    BGB Guest

    On 5/28/2012 11:15 PM, mike3 wrote:
    > Hi.
    >
    > I've heard about this, and wonder when is it right to use codes, and
    > when to use exceptions for reporting errors? I've heard various stuff,
    > such as that exceptions should only be used to indicate "exceptional"
    > conditions. Yet what does that mean? I've heard that, e.g. a user
    > inputting invalid input should not be considered "exceptional", but
    > something like running out of memory should be. Does this mean that if
    > we have a program, and we have a "parse()" function that parses a
    > string input by the user, that this function should return an error
    > code on parse failure, instead of throwing an exception? Yet we'll
    > probably also come across places where it's good to use an exception,
    > in the same program! Which means we get into _mixing error codes and
    > exceptions_. And what's the best way to do that?
    >


    maybe more like this:
    use error codes if it can be reasonably done so;
    use exceptions if error codes wont really work.

    usually, this means returning an error code if the operation can be
    handled as a no-op and otherwise the program can continue as normal
    (like, "well, that didn't work").

    use an exception if this represents a case where normal operation can no
    longer reasonably continue (all action past this point is no longer
    likely to be in a valid state, such as detecting that some internal
    program state is critically wrong).

    if it is not clear to use, probably I would opt with error codes.
    (usually, when an exception is needed, it is "fairly obvious").


    > Also, how exactly does one go about determining what is and is not
    > "exceptional"? Two examples were mentioned of things exceptional and
    > non-exceptional, but what about something else, like say in a game,
    > where you have a grid representing a game level, and a request for a
    > tile of the level is made with a coordinate that is off the map (like
    > a 64x64 map and something requests a tile at (100, 100).). Would it be
    > OK for the function working on the tile to throw? Or should it give an
    > "out of range" error code? And as for that mixing: consider, e.g. C++
    > and probably many other languages: a function has a single definite
    > return type. Suppose our grid had a function that extracts an
    > attribute from a cell. What to do when there's an out-of-bounds
    > request? Throw exception? See, what I've currently been doing, and
    > it's probably silly, is to use exceptions when our function needs to
    > return a value, and error codes when it could otherwise return "void".
    > This doesn't seem like a good idea. But what to do? Make every
    > function return an error code, using pointers to output variables to
    > store output, and only use exceptions for a rare few kinds of "system-
    > related" error? Yet one can hardly deny the niceness of being able to
    > say "x = f() +<foo>" (inside a "try" block, perhaps) instead of
    >
    > if(f(&x) != SUCCESS)
    > { // handle error }
    > x += foo;
    >
    > :)
    >
    > Note how we can easily get LONG methods full of repeated code with
    > error codes (repeated error handlers to handle similar errors at
    > various function calls calling error-code-emitting functions, if one
    > wants to be more graceful than simply aborting with an error to the
    > next level up (which complicates what error codes a function can
    > return, since it can return its own codes in addition to those
    > returned by the functions below it, and those may have functions below
    > THEM, and so on...).). And who likes duplicated code? eww. This seems
    > a disadvantage of error codes.
    >
    > Or, and this is what I've been thinking of, use exceptions for every
    > error that the user does not have control over, like invalid input
    > strings. Would that be OK or excessive use of exceptions? And if we
    > are to mix error codes and exceptions, does this mean we should have
    > the lists of codes and exceptions correspond + a translator to
    > translate between the two?



    if the function returns a void, use it to return an error code;
    if the function returns a pointer, one can potentially return NULL, and
    have another operation to fetch the actual error code (stored off in a
    variable somewhere);
    if the function returns a number, then it is a little harder, sometimes
    it can be ">=0 for success, <0 for error", but if the function may
    return the full range, it is a bit harder.

    one way I have handled it is to have it be similar to the pointer case,
    where a certain value (0 or -1), "may" represent an error, and whether
    or not it really does is determined by retrieving the error code.

    NaN is also a possible error value for floating-point numbers, but is
    rarely used this way.
     
    BGB, May 29, 2012
    #2
    1. Advertising

  3. mike3

    mike3 Guest

    On May 28, 11:10 pm, BGB <> wrote:
    <snip>
    > maybe more like this:
    > use error codes if it can be reasonably done so;
    > use exceptions if error codes wont really work.
    >


    So does this mean it is OK to use exceptions for errors in, say, a
    constructor, regardless of what the error is?
     
    mike3, May 29, 2012
    #3
  4. mike3

    BGB Guest

    On 5/29/2012 12:41 AM, mike3 wrote:
    > On May 28, 11:10 pm, BGB<> wrote:
    > <snip>
    >> maybe more like this:
    >> use error codes if it can be reasonably done so;
    >> use exceptions if error codes wont really work.
    >>

    >
    > So does this mean it is OK to use exceptions for errors in, say, a
    > constructor, regardless of what the error is?


    potentially.

    if for some reason the constructor can't actually do its thing, this may
    be a reasonable option.

    usually, I prefer "graceful" handling whenever possible, meaning that an
    exception would only be used in this case if the produced object would
    be invalid and there is no "more graceful" way to handle the situation.

    there is no solid rules to define this, and it may need to be evaluated
    on a case-by-case basis.
     
    BGB, May 29, 2012
    #4
  5. On 29.05.2012 06:15, mike3 wrote:
    > I've heard about this, and wonder when is it right to use codes, and
    > when to use exceptions for reporting errors? I've heard various stuff,
    > such as that exceptions should only be used to indicate "exceptional"
    > conditions. Yet what does that mean?


    Finally it is up to the programmer to take the decision.
    But there are some performance aspects as well as some considerations
    about exception safe code.

    Depending on your language, throwing an exception could be an expensive
    task. C++ is yet mostly harmless, but managed languages like Java or
    *.NET create an expensive stack trace at the time of the exception
    construction or at throw respectively. So it is in general a bad advise
    to throw and catch exceptions over and over in loops.

    Furthermore exceptions are an unexpected way of changing the execution
    flow. While this is intended in most cases there are some pitfalls. Most
    code is not fully exception safe. I.e. is shows undefined behavior if
    the exception occur at the evaluation of certain (sub-)expressions.
    Writing fully exception safe code can be almost as complicated than
    writing thread-safe code.
    So in fact you should know which of your functions throw exceptions and
    which don't. At the end, the advantage of the exceptions, easy code,
    might no longer be that large.


    > I've heard that, e.g. a user
    > inputting invalid input should not be considered "exceptional", but
    > something like running out of memory should be.


    Well, I dislike general statements like this.

    If a wrong user input causes the normal execution flow to be interrupted
    at a certain point, a exception might be quite OK. If the execution
    continues with the next input box that might be also become red,
    exceptions might not hit the nail on the head. You remember, no catch in
    a loop (over the controls).


    > Also, how exactly does one go about determining what is and is not
    > "exceptional"?


    You can't determine this. You have to /define/ this.
    What causes your program to abandon normal operation (for a while)?


    > non-exceptional, but what about something else, like say in a game,
    > where you have a grid representing a game level, and a request for a
    > tile of the level is made with a coordinate that is off the map (like
    > a 64x64 map and something requests a tile at (100, 100).). Would it be
    > OK for the function working on the tile to throw?


    Does this abort normal program flow?
    What is the proper action to be taken next?

    > Or should it give an
    > "out of range" error code? And as for that mixing: consider, e.g. C++
    > and probably many other languages: a function has a single definite
    > return type. Suppose our grid had a function that extracts an
    > attribute from a cell. What to do when there's an out-of-bounds
    > request? Throw exception?


    Unless your semantics have some default value which could be used to
    continue processing, you won't come around to abort the execution flow
    here. But it could be a good advice to check this before you call any
    function that will not work properly. I.e. you could turn the array
    bounds condition into a precondition which could be checked by an assertion.


    > But what to do? Make every
    > function return an error code, using pointers to output variables to
    > store output, and only use exceptions for a rare few kinds of "system-
    > related" error?


    Don't do that. Use exception where they make the code easier to read and
    easier to understand. And if you run into performance problems, then
    look for a work around. But in C++ this is unlikely as long as you do
    not abuse them extensively.
    A prominent exception to this rule are APIs that can cross language
    boundaries. In this case you mostly have no chance. You need error codes.

    Another rule of thumb: if throw and catch are close together with
    respect to the call stack it is more likely that an error code fit your
    needs. If they are well separated, then exceptions might be preferable.


    [...]
    > Would that be OK or excessive use of exceptions? And if we
    > are to mix error codes and exceptions, does this mean we should have
    > the lists of codes and exceptions correspond + a translator to
    > translate between the two?


    Converting an error code into an exception might be a good idea. But the
    other way around is most likely not.

    And another rule of thumb: the number of exceptions thrown during the
    processing of a complete request should be finite. I.e. it must not
    scale with the amount of data processed.


    Marcel
     
    Marcel Müller, May 29, 2012
    #5
  6. On Mon, 28 May 2012 21:15:00 -0700 (PDT), mike3 wrote:

    > I've heard about this, and wonder when is it right to use codes, and
    > when to use exceptions for reporting errors?


    Return code should be used under no circumstances.

    1. return codes cripple design on the callee's side
    2. they cuase massive code replication contaminating the source program on
    the client side
    3. they are unmaintainable (consider adding/removing a code value)
    4. they represent a distributed overhead causing less efficient programs on
    most of existing architectures

    > I've heard various stuff,
    > such as that exceptions should only be used to indicate "exceptional"
    > conditions. Yet what does that mean?


    Exceptional condition is when normal continuation would be impossible.

    As an example consider zero divide. It is exceptional because for x /=0
    there is no numeric value y such that y * 0 = x.

    > I've heard that, e.g. a user
    > inputting invalid input should not be considered "exceptional",


    That depends on whether continuation is possible. E.g. an improperly
    encoded UTF-8 character may be replaced by '?' or raise an exception
    causing the caller to sort things out. The choice depends on the
    application. The key question is: who is responsible for recovery?

    > but
    > something like running out of memory should be. Does this mean that if
    > we have a program, and we have a "parse()" function that parses a
    > string input by the user, that this function should return an error
    > code on parse failure, instead of throwing an exception?


    When the result would be invalid, parse should raise an exception, e.g.
    Syntax_Error with an appropriate message and error location indication.

    > Also, how exactly does one go about determining what is and is not
    > "exceptional"?


    You look at the contract of the thing. e.g. of operation /. If there is no
    way to implement the contract, that is exceptional [*]. Another way to put
    it: an exception is to propagate from where there is not enough information
    to handle it without crippling the design. When you implement file read
    operation. At the file end, you don't know what to do. You cannot continue
    reading, so you raise End_Error. The caller should have information how to
    react. If it does not, it let the exception propagate or raise another
    exception, etc.

    -----------
    * Exception fixes the contract by adding itself as a possible outcome.

    --
    Regards,
    Dmitry A. Kazakov
    http://www.dmitry-kazakov.de
     
    Dmitry A. Kazakov, May 29, 2012
    #6
  7. mike3

    Jorgen Grahn Guest

    ["Followup-To:" header set to comp.lang.c++.]
    On Tue, 2012-05-29, mike3 wrote:
    > Hi.
    >
    > I've heard about this, and wonder when is it right to use codes, and
    > when to use exceptions for reporting errors?


    Are you asking specifically about C++? I will assume "yes", but I get
    a bit confused by your crossposting to comp.programming -- what's the
    proper use of exceptions varies between languages (and cultures).

    > I've heard various stuff,
    > such as that exceptions should only be used to indicate "exceptional"
    > conditions. Yet what does that mean? I've heard that, e.g. a user
    > inputting invalid input should not be considered "exceptional", but
    > something like running out of memory should be. Does this mean that if
    > we have a program, and we have a "parse()" function that parses a
    > string input by the user, that this function should return an error
    > code on parse failure, instead of throwing an exception? Yet we'll
    > probably also come across places where it's good to use an exception,
    > in the same program! Which means we get into _mixing error codes and
    > exceptions_. And what's the best way to do that?
    >
    > Also, how exactly does one go about determining what is and is not
    > "exceptional"?


    I don't think you should try use the idea of "exceptional" conditions
    as a strict rule to apply. IIRC it was something Stroustrup came up with
    to explain how he thinks about it, but it's vague; you can debate
    what's exceptional or not for years.

    Some things are hard to set up general rules for. You have to deal
    with them on a case-by-case basis.

    > Two examples were mentioned of things exceptional and
    > non-exceptional, but what about something else, like say in a game,
    > where you have a grid representing a game level, and a request for a
    > tile of the level is made with a coordinate that is off the map (like
    > a 64x64 map and something requests a tile at (100, 100).). Would it be
    > OK for the function working on the tile to throw? Or should it give an
    > "out of range" error code?


    To me, it has more to do with things like:
    - are you going to take steps elsewhere to make out-of-bounds
    requests not happen? E.g. document "it's up to the caller
    to stay on the map"?
    - can it make sense not to handle the error locally?
    - would an error code be an unreasonable burden at the calling site,
    e.g. you really want to be able to say things like
    "get_tile(position).invert();" ?

    But it seems you say more or less this below!

    > And as for that mixing: consider, e.g. C++
    > and probably many other languages: a function has a single definite
    > return type. Suppose our grid had a function that extracts an
    > attribute from a cell. What to do when there's an out-of-bounds
    > request? Throw exception? See, what I've currently been doing, and
    > it's probably silly, is to use exceptions when our function needs to
    > return a value, and error codes when it could otherwise return "void".
    > This doesn't seem like a good idea. But what to do? Make every
    > function return an error code, using pointers to output variables to
    > store output, and only use exceptions for a rare few kinds of "system-
    > related" error? Yet one can hardly deny the niceness of being able to
    > say "x = f() + <foo>" (inside a "try" block, perhaps) instead of
    >
    > if(f(&x) != SUCCESS)
    > { // handle error }
    > x += foo;
    >
    > :)
    >
    > Note how we can easily get LONG methods full of repeated code with
    > error codes (repeated error handlers to handle similar errors at
    > various function calls calling error-code-emitting functions, if one
    > wants to be more graceful than simply aborting with an error to the
    > next level up (which complicates what error codes a function can
    > return, since it can return its own codes in addition to those
    > returned by the functions below it, and those may have functions below
    > THEM, and so on...).). And who likes duplicated code? eww. This seems
    > a disadvantage of error codes.
    >
    > Or, and this is what I've been thinking of, use exceptions for every
    > error that the user does not have control over, like invalid input
    > strings. Would that be OK or excessive use of exceptions? And if we
    > are to mix error codes and exceptions, does this mean we should have
    > the lists of codes and exceptions correspond + a translator to
    > translate between the two?


    As far as I can tell, you think about this pretty much like I do,
    except you're still trying to formalize it into some system of rules.
    Try not to do that for a while, and see how it feels.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, May 29, 2012
    #7
  8. mike3

    Adam Skutt Guest

    On May 29, 1:10 am, BGB <> wrote:
    > On 5/28/2012 11:15 PM, mike3 wrote:
    >
    > > Hi.

    >
    > > I've heard about this, and wonder when is it right to use codes, and
    > > when to use exceptions for reporting errors? I've heard various stuff,
    > > such as that exceptions should only be used to indicate "exceptional"
    > > conditions. Yet what does that mean? I've heard that, e.g. a user
    > > inputting invalid input should not be considered "exceptional", but
    > > something like running out of memory should be. Does this mean that if
    > > we have a program, and we have a "parse()" function that parses a
    > > string input by the user, that this function should return an error
    > > code on parse failure, instead of throwing an exception? Yet we'll
    > > probably also come across places where it's good to use an exception,
    > > in the same program! Which means we get into _mixing error codes and
    > > exceptions_. And what's the best way to do that?

    >
    > maybe more like this:
    > use error codes if it can be reasonably done so;
    > use exceptions if error codes wont really work.


    Nonsense. A function should only return a value if the caller can use
    the return value to further its own computation. It is very rare for
    an error code to be useful to the caller, much less all of the codes
    returned by a function. Hence, they should be exceptions because
    stack unwinding will be needed.

    > usually, this means returning an error code if the operation can be
    > handled as a no-op and otherwise the program can continue as normal
    > (like, "well, that didn't work").


    If the error can and should be treated as a no-op then there is no
    reason to return anything at all.

    > if it is not clear to use, probably I would opt with error codes.
    > (usually, when an exception is needed, it is "fairly obvious").


    This is precisely backwards. Return values should have clear,
    obvious, and unambiguous usage. If you cannot determine what the
    caller would do with the return value, then odds are good they will
    "pass the buck" and therefore an exception is the right thing.

    > > Or, and this is what I've been thinking of, use exceptions for every
    > > error that the user does not have control over, like invalid input
    > > strings. Would that be OK or excessive use of exceptions? And if we
    > > are to mix error codes and exceptions, does this mean we should have
    > > the lists of codes and exceptions correspond + a translator to
    > > translate between the two?

    >
    > if the function returns a void, use it to return an error code;


    This is nonsense. I assume you meant, "Change the return type to be
    an error code" but I honestly have no clue.

    > if the function returns a pointer, one can potentially return NULL, and
    > have another operation to fetch the actual error code (stored off in a
    > variable somewhere);


    This requires either extra parameters or a lot of ugly work to create
    thread-safe behavior. Which is why error codes are a bad idea. Using
    them simply pollutes calling code for no clear benefit, especially
    when stack unwinding is necessary (which is the most common case).

    Adam
     
    Adam Skutt, May 29, 2012
    #8
  9. mike3

    Adam Skutt Guest

    On May 29, 12:15 am, mike3 <> wrote:
    > Hi.
    >
    > I've heard about this, and wonder when is it right to use codes, and
    > when to use exceptions for reporting errors?


    You should almost always use exceptions. The main reason to use error
    codes in C++ would be due to compatibility concerns with C frameworks,
    or so that C-compatible wrappers can be provided for your C++ code.

    I've heard various stuff,
    > such as that exceptions should only be used to indicate "exceptional"
    > conditions. Yet what does that mean?


    It means that anything other than what the function would return if it
    completed normally, or did not fail. The question you should ask
    yourself is: "What would the function return if it simply could not
    fail?" The answer to that question (if any) is the return value.
    Anything else should almost certainly be an exception. Anything that
    will (really might) require stack unwinding to handle should also be
    an exception.

    > I've heard that, e.g. a user
    > inputting invalid input should not be considered "exceptional", but
    > something like running out of memory should be. Does this mean that if
    > we have a program, and we have a "parse()" function that parses a
    > string input by the user, that this function should return an error
    > code on parse failure, instead of throwing an exception?


    The result of a parse function is a data structure representing the
    parsed input (e.g., a parse tree). If the function cannot produce a
    parse tree, and the caller needs a parse tree to continue on their
    computation (i.e., failure cannot be sensibly replaced with an empty
    tree) than an exception should be thrown.

    In this case, it's not necessarily guaranteed that the function that
    called parse() will be the function that prompts the user for input.
    It's also not guaranteed that prompting the user for replacement input
    is possible. If your input comes from a pipe, then you have no way to
    prompt the user and only one input. In this case, termination is
    likely the only sensible response for the parse failure. An exception
    should be used here since stack winding is not only a probable
    response, but a likely response, to a parsing failure.

    > Yet we'll
    > probably also come across places where it's good to use an exception,
    > in the same program! Which means we get into _mixing error codes and
    > exceptions_. And what's the best way to do that?


    Don't. If you must, it is probably best to convert error codes to
    exceptions and not vice-versa. This should only come up if you must
    interface with legacy systems or C libraries.

    >
    > Also, how exactly does one go about determining what is and is not
    > "exceptional"? Two examples were mentioned of things exceptional and
    > non-exceptional, but what about something else, like say in a game,
    > where you have a grid representing a game level, and a request for a
    > tile of the level is made with a coordinate that is off the map (like
    > a 64x64 map and something requests a tile at (100, 100).). Would it be
    > OK for the function working on the tile to throw?


    Absolutely.

    > Or should it give an "out of range" error code?


    Doubtful. Code that provided an invalid input either has a bug (so
    must be fixed) or received invalid input from the user. In either
    case, an exception is better way to structure a response to the error
    condition.

    > Yet one can hardly deny the niceness of being able to
    > say "x = f() + <foo>" (inside a "try" block, perhaps) instead of
    >
    > if(f(&x) != SUCCESS)
    >  { // handle error }
    > x += foo;
    >
    > :)
    >


    Precisely why one shouldn't use error codes.

    > Or, and this is what I've been thinking of, use exceptions for every
    > error that the user does not have control over, like invalid input
    > strings. Would that be OK or excessive use of exceptions?


    If I understood you, then buggy functions require program termination
    to replace the buggy application[1]. Exceptions will unwind the stack
    to terminate the program. Therefore, one should use an exception in
    response to invalid input that didn't come from the user.

    Though one should also use exceptions to signify invalid input that
    did come from the user, because input is rarely accepted in the exact
    same function that it is validated.

    > And if we
    > are to mix error codes and exceptions, does this mean we should have
    > the lists of codes and exceptions correspond + a translator to
    > translate between the two?


    No.

    Adam

    [1] Typically, a few unique systems aside.
     
    Adam Skutt, May 29, 2012
    #9
  10. mike3

    BGB Guest

    On 5/29/2012 9:16 AM, Adam Skutt wrote:
    > On May 29, 1:10 am, BGB<> wrote:
    >> On 5/28/2012 11:15 PM, mike3 wrote:
    >>
    >>> Hi.

    >>
    >>> I've heard about this, and wonder when is it right to use codes, and
    >>> when to use exceptions for reporting errors? I've heard various stuff,
    >>> such as that exceptions should only be used to indicate "exceptional"
    >>> conditions. Yet what does that mean? I've heard that, e.g. a user
    >>> inputting invalid input should not be considered "exceptional", but
    >>> something like running out of memory should be. Does this mean that if
    >>> we have a program, and we have a "parse()" function that parses a
    >>> string input by the user, that this function should return an error
    >>> code on parse failure, instead of throwing an exception? Yet we'll
    >>> probably also come across places where it's good to use an exception,
    >>> in the same program! Which means we get into _mixing error codes and
    >>> exceptions_. And what's the best way to do that?

    >>
    >> maybe more like this:
    >> use error codes if it can be reasonably done so;
    >> use exceptions if error codes wont really work.

    >
    > Nonsense. A function should only return a value if the caller can use
    > the return value to further its own computation. It is very rare for
    > an error code to be useful to the caller, much less all of the codes
    > returned by a function. Hence, they should be exceptions because
    > stack unwinding will be needed.
    >


    not always, it depends.

    if you need to unwind the stack either way, then an exception may make
    sense. if not, it is probably not a good answer.


    >> usually, this means returning an error code if the operation can be
    >> handled as a no-op and otherwise the program can continue as normal
    >> (like, "well, that didn't work").

    >
    > If the error can and should be treated as a no-op then there is no
    > reason to return anything at all.
    >


    usually, the error code will indicate a success/failure in this case.

    it is often useful to be able to detect "well, that didn't work",
    without needing to be like "on no, stuff has gone terribly wrong".


    an example is trying to open a file and searching through a path:
    the program may try opening the file along various paths, and see if any
    of them work;
    in this case, we want to know whether or not the file has been opened
    successfully, without needing to catch for every iteration of the loop.


    >> if it is not clear to use, probably I would opt with error codes.
    >> (usually, when an exception is needed, it is "fairly obvious").

    >
    > This is precisely backwards. Return values should have clear,
    > obvious, and unambiguous usage. If you cannot determine what the
    > caller would do with the return value, then odds are good they will
    > "pass the buck" and therefore an exception is the right thing.
    >


    often, if one is using an error code, the operation was probably just
    handled as a no-op anyways.

    one can use an exception if the situation is sufficiently critical to
    where the caller merely carrying on as before would not be a desirable
    outcome.

    very often, there is no reason to care, and it is better to not burden
    the caller with the results, except when they actually care whether or
    not the operation succeeded.


    >>> Or, and this is what I've been thinking of, use exceptions for every
    >>> error that the user does not have control over, like invalid input
    >>> strings. Would that be OK or excessive use of exceptions? And if we
    >>> are to mix error codes and exceptions, does this mean we should have
    >>> the lists of codes and exceptions correspond + a translator to
    >>> translate between the two?

    >>
    >> if the function returns a void, use it to return an error code;

    >
    > This is nonsense. I assume you meant, "Change the return type to be
    > an error code" but I honestly have no clue.
    >


    fair enough, that could have been written better.

    I was responding in context of a prior statement, which basically said
    that the OP was using return codes in cases where the function would
    otherwise return void.

    so, in this case, a person might consider using a return code instead of
    a void.


    >> if the function returns a pointer, one can potentially return NULL, and
    >> have another operation to fetch the actual error code (stored off in a
    >> variable somewhere);

    >
    > This requires either extra parameters or a lot of ugly work to create
    > thread-safe behavior. Which is why error codes are a bad idea. Using
    > them simply pollutes calling code for no clear benefit, especially
    > when stack unwinding is necessary (which is the most common case).
    >


    I disagree that stack-unwinding is the most common case.
    IME, no-op is the most common case, and if the error code is even
    checked, it is usually done so to determine a success/failure status (so
    that the caller logic can determine whether or not to try a different
    option, ...).

    as for "in a variable somewhere":
    typically, this would be an object field or thread-local variable.

    an example would be, say, an object with an "obj->getError()" method or
    similar, or a "fooGetError()" function which returns the contents of a
    TLS variable, ...


    then it is thread-safe...

    I didn't say here that it would be a global variable or similar, which
    wouldn't be thread-safe.
     
    BGB, May 29, 2012
    #10
  11. mike3

    Adam Skutt Guest

    On May 29, 10:45 am, BGB <> wrote:
    > On 5/29/2012 9:16 AM, Adam Skutt wrote:
    > > On May 29, 1:10 am, BGB<>  wrote:
    > >> maybe more like this:
    > >> use error codes if it can be reasonably done so;
    > >> use exceptions if error codes wont really work.

    >
    > > Nonsense.  A function should only return a value if the caller can use
    > > the return value to further its own computation.  It is very rare for
    > > an error code to be useful to the caller, much less all of the codes
    > > returned by a function.  Hence, they should be exceptions because
    > > stack unwinding will be needed.

    >
    > not always, it depends.


    On what, exactly?
    >


    > if you need to unwind the stack either way, then an exception may make
    > sense.


    I fail to see how making the programmer manually do what the language
    does automatically is worthwhile. You're going to have to give
    examples, and if they're not relevant to general-case programming then
    please don't waste anyone's time.


    > if not, it is probably not a good answer.
    >


    Why? You claim this as a tautology and provide zero evidence. The OP
    quite clearly and plainly pointed out many problems with using error
    codes, which you have utterly failed to rebut nor managed to
    demonstrate any positive aspects that allow us to overlook their
    flaws.

    > >> usually, this means returning an error

    code if the operation can be
    > >> handled as a no-op and otherwise the program can continue as normal
    > >> (like, "well, that didn't work").

    >
    > > If the error can and should be treated as a no-op then there is no
    > > reason to return anything at all.

    >
    > usually, the error code will indicate a success/failure in this case.
    >
    > it is often useful to be able to detect "well, that didn't work",
    > without needing to be like "on no, stuff has gone terribly wrong".


    Huh? This is a complete non-sequitur, as best as I can tell. If I
    call a function x() and its behavior is to either: a) succeed b) do
    nothing, then why would it ever need to return a status code?

    Of course, your original statement didn't really make any sense
    either, so it's quite likely I simply have no idea what you were
    trying to say in the first place.

    >
    > an example is trying to open a file and searching through a path:
    > the program may try opening the file along various paths, and see if any
    > of them work;
    > in this case, we want to know whether or not the file has been opened
    > successfully, without needing to catch for every iteration of the loop.
    >


    Nonsense. There's never a need to "detect[ing] 'well, that didn't
    work', without needing to be like 'on no, stuff has gone terribly
    wrong'." This would be because the difference between the a retryable
    error and a fatal error is entirely in the hands of the calling code,
    not the called function. The response of the file open function should
    be the same in either case, because it has no clue what is
    appropriate.

    You claim an catch block is inappropriate here, but you give no reason
    why. I fail to see any reason why it is inappropriate whatsoever. It
    doesn't even take up more space over if/else in your example.

    > often, if one is using an error code, the operation was probably just
    > handled as a no-op anyways.


    Which is another reason why error codes are bad, there's a good chance
    the programmer will ignore them, leading to undefined behavior later
    on.

    >
    > one can use an exception if the situation is sufficiently critical to
    > where the caller merely carrying on as before would not be a desirable
    > outcome.
    >


    Except it is generally impossible for the called function to know
    whether the caller wishes to carry on afterwards or not. Hence why
    you should only return input that is useful to everyone and toss an
    exception otherwise. People who wish to carry on can install catch
    blocks. Everyone else gets precisely what they want.

    > very often, there is no reason to care, and it is better to not burden
    > the caller with the results, except when they actually care whether or
    > not the operation succeeded.


    Which is exactly what exceptions accomplish! The fact that my code
    continued executing at the next statement means that the called
    function succeeded. It also means I never have to worry about
    "exceptional" conditions unless I can actually provide a meaningful
    response to the condition. If I cannot, then I can pretend that it
    does not exist and go on with my lives.

    This results in less code, and practically never more code, for the
    caller and called function. On that basis alone, exceptions are
    superior.

    > I disagree that stack-unwinding is the most common case.


    You're welcome to present evidence otherwise but you're going to be
    hard pressed to do so.

    > IME, no-op is the most common case, and if the error code is even
    > checked,


    If you're going to argue from this basis, you first have to show that
    it is correct to ignore the error codes. Tons of software ignores
    error codes even when it is not correct to do so. You're quite
    honestly adding to your already enormous burden.

    > it is usually done so to determine a success/failure status (so
    > that the caller logic can determine whether or not to try a different
    > option, ...).


    Or clean it's resources and manually unwind. Or just as likely,
    because that's so difficult to do manually, call abort() or a similar
    function to end the world.

    >
    > as for "in a variable somewhere":
    > typically, this would be an object field or thread-local variable.
    >
    > an example would be, say, an object with an "obj->getError()" method or
    > similar, or a "fooGetError()" function which returns the contents of a
    > TLS variable, ...
    >
    > then it is thread-safe...
    >


    Both are considerable amounts of work for totally unclear benefit.

    > I didn't say here that it would be a global variable or similar, which
    > wouldn't be thread-safe.


    You described essentially the traditional C errno interface, which
    requires considerable gymnastics to achieve thread-safety.

    Adam
     
    Adam Skutt, May 29, 2012
    #11
  12. mike3

    BGB Guest

    On 5/29/2012 10:20 AM, Adam Skutt wrote:
    > On May 29, 10:45 am, BGB<> wrote:
    >> On 5/29/2012 9:16 AM, Adam Skutt wrote:
    >>> On May 29, 1:10 am, BGB<> wrote:
    >>>> maybe more like this:
    >>>> use error codes if it can be reasonably done so;
    >>>> use exceptions if error codes wont really work.

    >>
    >>> Nonsense. A function should only return a value if the caller can use
    >>> the return value to further its own computation. It is very rare for
    >>> an error code to be useful to the caller, much less all of the codes
    >>> returned by a function. Hence, they should be exceptions because
    >>> stack unwinding will be needed.

    >>
    >> not always, it depends.

    >
    > On what, exactly?


    what the code does.

    >>

    >
    >> if you need to unwind the stack either way, then an exception may make
    >> sense.

    >
    > I fail to see how making the programmer manually do what the language
    > does automatically is worthwhile. You're going to have to give
    > examples, and if they're not relevant to general-case programming then
    > please don't waste anyone's time.
    >


    ok, consider a function:
    byte *Foo_ReadInFile(char *name, int &sz);

    which returns NULL if the file failed to load.

    now, we have a path like:
    char *foo_basepaths[256];
    int foo_num_basepaths;

    ....


    SomeObjectType *Foo_LoadSomeFileData(char *name)
    {
    char tb[256];
    SomeObjectType *tmp;
    char *buf;
    int i, sz;

    for(i=0, buf=NULL; !buf && i<foo_num_basepaths; i++)
    {
    snprintf(tb, 256, "%s/%s", foo_basepaths, name);
    buf=Foo_ReadInFile(tb, sz);
    //would we rather have had ReadInFile throw here?
    }

    if(!buf)
    {
    //what do we do here, return or throw
    return(NULL); //ok, how about we let caller decide?
    }

    tmp=Foo_ParseObjectFromBuffer(buf, sz);
    //now, what here?
    return(tmp); //ok, return whatever we got.
    }

    and, in the caller:
    SomeObjectType *Baz_TryLoadSomeData(char *name)
    {
    char tb[256];
    SomeObjectType *tmp;

    //see if we can load it as a ".foo" file.
    snprintf(tb, 256, "%s.foo", name);
    tmp=Foo_LoadSomeFileData(name);
    if(tmp)return(tmp); //got something

    //well, is is a ".bar" file?
    snprintf(tb, 256, "%s.bar", name);
    tmp=Bar_LoadSomeFileData(name);
    if(tmp)return(tmp); //got something

    ...

    //ok, couldn't find anything, what now?
    //maybe?
    baz_errno=BAZ_COULDNTFINDFILE;
    return(NULL);
    }

    and so on...


    a more concrete example:
    consider we are trying to load a 3D model, but don't know in advance
    what type of 3D model we are trying to load.

    or, we are trying to load a graphic image, but were not given the full
    path or the file extension (it could be in one of several locations, or
    a PNG, or a JPG, or a BMP, or a TGA, ...).

    sometimes, the graphic loading may itself be conditional, say:
    did this texture have a normal-map image?
    we know it didn't, if none could be loaded, but otherwise it is no big
    deal (the texture is used without a normal-map).


    an alternate scenario would be, say, if one particular branch of a
    programs' drawing code depends on shaders, but the user's system doesn't
    have shaders (say, because they have an old/crappy video card)?

    well, simplest option would just be to return an error (like, "hey, this
    wont work"), with the application falling back to an alternate path:
    "well, can we draw it without the shaders then?".

    then, if this fails, maybe then something is broken, then one can throw
    an exception, or maybe it will end up in the main loop with an error
    status "hey, the rendering failed", then the main loop might decide
    "well, the renderer apparently isn't working, so have the application exit".

    now, exceptions could also work here, say the first piece of logic
    throws a "DontHaveShaders" exception or similar, and some code up the
    tree catches it and uses the alternate rendering path, but is this less
    effort, or more efficient?...


    the alternative strategy would be to always do things in the caller, like:
    if(foo->DoWeHaveShaders())
    {
    foo->DoItWithShaders();
    }else
    {
    foo->DoItWithoutShaders();
    }


    but, this may require separate functions to handle checking and
    performing the operation, rather than say:

    if(foo->DoItWithShaders()<0)
    {
    if(foo->DoItWithoutShaders()<0)
    {
    //failed to render anything
    return(FOO_FAILEDTORENDER);
    }
    }
    return(FOO_SUCCESS);


    >
    >> if not, it is probably not a good answer.
    >>

    >
    > Why? You claim this as a tautology and provide zero evidence. The OP
    > quite clearly and plainly pointed out many problems with using error
    > codes, which you have utterly failed to rebut nor managed to
    > demonstrate any positive aspects that allow us to overlook their
    > flaws.
    >


    I say it depends on the situation.

    and I am not saying that one doesn't use exceptions, only that a person
    may need to evaluate it based on which is more likely to be more
    convenient in a given situation.


    I am not saying anything is universal rules here, but all depends on
    whatever is more convenient at the moment.


    >>>> usually, this means returning an error

    > code if the operation can be
    >>>> handled as a no-op and otherwise the program can continue as normal
    >>>> (like, "well, that didn't work").

    >>
    >>> If the error can and should be treated as a no-op then there is no
    >>> reason to return anything at all.

    >>
    >> usually, the error code will indicate a success/failure in this case.
    >>
    >> it is often useful to be able to detect "well, that didn't work",
    >> without needing to be like "on no, stuff has gone terribly wrong".

    >
    > Huh? This is a complete non-sequitur, as best as I can tell. If I
    > call a function x() and its behavior is to either: a) succeed b) do
    > nothing, then why would it ever need to return a status code?
    >
    > Of course, your original statement didn't really make any sense
    > either, so it's quite likely I simply have no idea what you were
    > trying to say in the first place.
    >


    fallback logic.


    whenever something doesn't work, the logic can fallback to trying an
    alternate (less preferred) strategy, usually until something either
    works, or all immediately available options are exhausted.


    often, using an exception will make more sense if the situation is more
    like: it either has to work, or things can not continue.

    but, this likely depends a lot more on what the program is doing.


    >>
    >> an example is trying to open a file and searching through a path:
    >> the program may try opening the file along various paths, and see if any
    >> of them work;
    >> in this case, we want to know whether or not the file has been opened
    >> successfully, without needing to catch for every iteration of the loop.
    >>

    >
    > Nonsense. There's never a need to "detect[ing] 'well, that didn't
    > work', without needing to be like 'on no, stuff has gone terribly
    > wrong'." This would be because the difference between the a retryable
    > error and a fatal error is entirely in the hands of the calling code,
    > not the called function. The response of the file open function should
    > be the same in either case, because it has no clue what is
    > appropriate.
    >
    > You claim an catch block is inappropriate here, but you give no reason
    > why. I fail to see any reason why it is inappropriate whatsoever. It
    > doesn't even take up more space over if/else in your example.
    >


    I disagree.

    trying things and seeing what works and what doesn't is actually fairly
    common IME.

    this is partly because some things are fairly common, like performing an
    operation with only partial information, and the program may have to
    probe around a little to figure out how exactly to go about doing it.


    >> often, if one is using an error code, the operation was probably just
    >> handled as a no-op anyways.

    >
    > Which is another reason why error codes are bad, there's a good chance
    > the programmer will ignore them, leading to undefined behavior later
    > on.
    >


    only if the operation is likely to be critical for correct operation, in
    which case one may need an exception.

    many times, things are not critical, or may simply be a matter of
    "Quality Of Experience" or similar, and even if the error code is
    ignored, this may not actually be all that much of a problem (the error
    code then being more like "did X go through successfully?" check).

    sometimes, the issue may even just be something like "the amount of work
    to be done ran over the time limit, so we bailed out early", which would
    unlikely hinder further operation.

    likewise for, say, "there were no more sound mixer channels available,
    so the sound effect couldn't be played" (usually only happens if the
    sound output is fairly noisy anyways, so the user is unlikely to notice
    the missing sound effect).

    although hardly critical to operation, code "may" care that this has
    happened (say, an outer part of the rendering loop may be like "stuff is
    running over the time limit, so drop the quality settings a little").


    granted, these types of situations may be handled by status flags
    instead (say, we have a "World" object, which may set flags in the
    object indicating that some parts of the process were taking too long to
    render, ...).


    >>
    >> one can use an exception if the situation is sufficiently critical to
    >> where the caller merely carrying on as before would not be a desirable
    >> outcome.
    >>

    >
    > Except it is generally impossible for the called function to know
    > whether the caller wishes to carry on afterwards or not. Hence why
    > you should only return input that is useful to everyone and toss an
    > exception otherwise. People who wish to carry on can install catch
    > blocks. Everyone else gets precisely what they want.
    >


    I still say, it depends.


    if they care, they may also check the return status, and if they don't
    and something breaks, well, that may just be a problem which needs to be
    fixed.

    the other side of this coin is an uncaught exception which is prone to
    blow up the application, which can be very annoying if it is due to
    "silly little things which don't otherwise impact the apps' continued
    functioning".

    like, say, application crashes due to an uncaught
    "ShadowNotDrawnTimeout" exception, because some object off in the
    background didn't draw a shadow before the time limit (which, very
    likely, the user would hardly even notice that it is missing).

    sometimes, we want some of these sorts of conditions to just disappear
    into the background noise.


    hence, why a distinction can be made between things which are and are
    not likely to impact continued and correct operation of the application.


    >> very often, there is no reason to care, and it is better to not burden
    >> the caller with the results, except when they actually care whether or
    >> not the operation succeeded.

    >
    > Which is exactly what exceptions accomplish! The fact that my code
    > continued executing at the next statement means that the called
    > function succeeded. It also means I never have to worry about
    > "exceptional" conditions unless I can actually provide a meaningful
    > response to the condition. If I cannot, then I can pretend that it
    > does not exist and go on with my lives.
    >
    > This results in less code, and practically never more code, for the
    > caller and called function. On that basis alone, exceptions are
    > superior.
    >


    as noted elsewhere:
    it depends on if the next statement actually depends on the prior
    statement having succeeded.

    it it doesn't, do we need to care?


    >> I disagree that stack-unwinding is the most common case.

    >
    > You're welcome to present evidence otherwise but you're going to be
    > hard pressed to do so.
    >
    >> IME, no-op is the most common case, and if the error code is even
    >> checked,

    >
    > If you're going to argue from this basis, you first have to show that
    > it is correct to ignore the error codes. Tons of software ignores
    > error codes even when it is not correct to do so. You're quite
    > honestly adding to your already enormous burden.
    >
    >> it is usually done so to determine a success/failure status (so
    >> that the caller logic can determine whether or not to try a different
    >> option, ...).

    >
    > Or clean it's resources and manually unwind. Or just as likely,
    > because that's so difficult to do manually, call abort() or a similar
    > function to end the world.
    >


    "abort()" is often the worst option, from a "Quality Of Experience" POV,
    as then the user has an app which simply dumps them back at the desktop
    at the first sign of trouble, and even more annoying, "abort()" will
    often not trap in the debugger either (unlike an uncaught exception).

    often, from a QOE POV, it is better to have an application which tries
    to compensate for whatever might go wrong, only "giving up" when it is
    clearly the case that it can't "work as intended" (an example would be
    failing to find files that it needs to start up, or failing to create
    the main window or initialize the renderer or similar).


    >>
    >> as for "in a variable somewhere":
    >> typically, this would be an object field or thread-local variable.
    >>
    >> an example would be, say, an object with an "obj->getError()" method or
    >> similar, or a "fooGetError()" function which returns the contents of a
    >> TLS variable, ...
    >>
    >> then it is thread-safe...
    >>

    >
    > Both are considerable amounts of work for totally unclear benefit.
    >
    >> I didn't say here that it would be a global variable or similar, which
    >> wouldn't be thread-safe.

    >
    > You described essentially the traditional C errno interface, which
    > requires considerable gymnastics to achieve thread-safety.
    >


    traditionally, yes.


    most modern C compilers essentially have errno as a macro which refers
    to a thread-local variable (typically making a function call in the
    process).
     
    BGB, May 29, 2012
    #12
  13. mike3

    Ian Collins Guest

    On 05/30/12 02:42 AM, Adam Skutt wrote:
    > On May 29, 12:15 am, mike3<> wrote:
    >> Hi.
    >>
    >> I've heard about this, and wonder when is it right to use codes, and
    >> when to use exceptions for reporting errors?

    >
    > You should almost always use exceptions. The main reason to use error
    > codes in C++ would be due to compatibility concerns with C frameworks,
    > or so that C-compatible wrappers can be provided for your C++ code.
    >
    > I've heard various stuff,
    >> such as that exceptions should only be used to indicate "exceptional"
    >> conditions. Yet what does that mean?

    >
    > It means that anything other than what the function would return if it
    > completed normally, or did not fail. The question you should ask
    > yourself is: "What would the function return if it simply could not
    > fail?" The answer to that question (if any) is the return value.
    > Anything else should almost certainly be an exception. Anything that
    > will (really might) require stack unwinding to handle should also be
    > an exception.


    I generally agree with you but this being programming, there are always
    exceptions to the rule. One would be were it is relatively expensive to
    check if an operation will succeed before attempting it. A good example
    of this is insertion into a set or map were both the resulting position
    and whether the insertion succeeded are returned.

    --
    Ian Collins
     
    Ian Collins, May 29, 2012
    #13
  14. mike3

    Adam Skutt Guest

    On May 29, 3:35 pm, Ian Collins <> wrote:
    > On 05/30/12 02:42 AM, Adam Skutt wrote:
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > On May 29, 12:15 am, mike3<>  wrote:
    > >> Hi.

    >
    > >> I've heard about this, and wonder when is it right to use codes, and
    > >> when to use exceptions for reporting errors?

    >
    > > You should almost always use exceptions.  The main reason to use error
    > > codes in C++ would be due to compatibility concerns with C frameworks,
    > > or so that C-compatible wrappers can be provided for your C++ code.

    >
    > > I've heard various stuff,
    > >> such as that exceptions should only be used to indicate "exceptional"
    > >> conditions. Yet what does that mean?

    >
    > > It means that anything other than what the function would return if it
    > > completed normally, or did not fail.  The question you should ask
    > > yourself is: "What would the function return if it simply could not
    > > fail?"  The answer to that question (if any) is the return value.
    > > Anything else should almost certainly be an exception.  Anything that
    > > will (really might) require stack unwinding to handle should also be
    > > an exception.

    >
    > I generally agree with you but this being programming, there are always
    > exceptions to the rule.  One would be were it is relatively expensive to
    > check if an operation will succeed before attempting it.  A good example
    > of this is insertion into a set or map were both the resulting position
    > and whether the insertion succeeded are returned.


    I think this is consistent with my guidelines when you take the full
    API of the set and map classes into consideration. One thing I didn't
    mention is that when designing class methods, one must consider the
    contract and semantics of the whole class as well. This is a good
    example of where one must think more carefully about what a function
    is trying to do and how it will be used, though. In this case, I
    would argue that inserting a duplicate is still a case where the
    method cannot fail, since the requested value is still in the set
    after the method returns.

    Adam
     
    Adam Skutt, May 29, 2012
    #14
  15. mike3

    Luca Risolia Guest

    On 29/05/2012 06:15, mike3 wrote:
    > if(f(&x) != SUCCESS)
    > { // handle error }
    > x += foo;
    >
    > :)
    >
    > Note how we can easily get LONG methods full of repeated code with
    > error codes (repeated error handlers to handle similar errors at
    > various function calls calling error-code-emitting functions, if one
    > wants to be more graceful than simply aborting with an error to the
    > next level up (which complicates what error codes a function can
    > return, since it can return its own codes in addition to those
    > returned by the functions below it, and those may have functions below
    > THEM, and so on...).). And who likes duplicated code? eww. This seems
    > a disadvantage of error codes.


    As a note, an "exception" does not necessarily represents a failure. For
    example, you can throw an exception to jump out of a recursive search
    algorithm when the searched value is found:

    void find_(Node* root, const char* str) {
    if (!root)
    return;
    if (!strcmp(str, root->str))
    throw root;
    find_(root->left, str);
    find_(root->right, str);
    }

    Node* find(Node* root, const char* str) {
    try {
    find_(root, str);
    } catch (Node* p) {
    return p;
    }
    throw not_found();
    }
     
    Luca Risolia, May 29, 2012
    #15
  16. mike3

    mike3 Guest

    On May 29, 6:24 am, Jorgen Grahn <> wrote:
    > ["Followup-To:" header set to comp.lang.c++.]

    <snip>
    > Are you asking specifically about C++?  I will assume "yes", but I get
    > a bit confused by your crossposting to comp.programming -- what's the
    > proper use of exceptions varies between languages (and cultures).
    >


    Yes, my eye was toward C++.

    <snip>
    > I don't think you should try use the idea of "exceptional" conditions
    > as a strict rule to apply. IIRC it was something Stroustrup came up with
    > to explain how he thinks about it, but it's vague; you can debate
    > what's exceptional or not for years.
    >
    > Some things are hard to set up general rules for.  You have to deal
    > with them on a case-by-case basis.
    >

    <snip>

    But what is the process for dealing with each case? You need some
    way to reason about the cases.

    > To me, it has more to do with things like:
    > - are you going to take steps elsewhere to make out-of-bounds
    >   requests not happen?  E.g. document "it's up to the caller
    >   to stay on the map"?


    What happens if we do that -- take steps elsewhere to make sure
    those requests don't happen? As that just makes sense to do.

    > - can it make sense not to handle the error locally?
    > - would an error code be an unreasonable burden at the calling site,
    >   e.g. you really want to be able to say things like
    >   "get_tile(position).invert();" ?
    >


    The trouble with error codes, as I see it, is that they can lead to
    lots
    of duplicated code. If you have a function that makes several calls
    to error-code-returning functions, then you need a handler around
    EVERY call. If the behavior of these handlers is similar, then you
    have code duplication. And duplicated code is Bad(tm). Not to
    mention that all those handlers generally makes the code more
    difficult to read, and can also lead to "long methods", another "bad"
    thing. (e.g. if you have, say, a 10-line handler and there's 10 calls
    there, then you get a 110-line Long Function. Ouch!)

    > But it seems you say more or less this below!
    >

    <snip>

    > As far as I can tell, you think about this pretty much like I do,
    > except you're still trying to formalize it into some system of rules.
    > Try not to do that for a while, and see how it feels.
    >


    Yet the approach I was using seems like a silly one (error codes
    for everything but what returns a value/constructors/etc.). "Silly"
    because it doesn't seem consistent or "inconsistent but in the right
    way". It means you could be easily, haphazardly mixing together
    operations that give error codes and that throw exceptions without
    any overarching logic.

    And also, I've noticed that with this "mix error codes and exceptions"
    thing, that I seem to find myself adding a translation layer to
    translate
    between the two and having a corresponding exception object for every
    error code, which makes it more difficult to add new exception/error
    conditions since we have to update all those lists. Is this the wrong
    way
    to go about it? If so, what's a better way to?
     
    mike3, May 29, 2012
    #16
  17. mike3

    Adam Skutt Guest

    On May 29, 2:47 pm, BGB <> wrote:
    > On 5/29/2012 10:20 AM, Adam Skutt wrote:
    > > On May 29, 10:45 am, BGB<>  wrote:
    > >> if you need to unwind the stack either way, then an exception may make
    > >> sense.

    >
    > > I fail to see how making the programmer manually do what the language
    > > does automatically is worthwhile.  You're going to have to give
    > > examples, and if they're not relevant to general-case programming then
    > > please don't waste anyone's time.

    >
    > ok, consider a function:
    > byte *Foo_ReadInFile(char *name, int &sz);
    >
    > which returns NULL if the file failed to load.
    >
    > now, we have a path like:
    > char *foo_basepaths[256];
    > int foo_num_basepaths;
    >
    > ...
    >
    > SomeObjectType *Foo_LoadSomeFileData(char *name)
    > {
    >         char tb[256];
    >         SomeObjectType *tmp;
    >         char *buf;
    >         int i, sz;
    >
    >         for(i=0, buf=NULL; !buf && i<foo_num_basepaths; i++)
    >         {
    >                 snprintf(tb, 256, "%s/%s", foo_basepaths, name);
    >                 buf=Foo_ReadInFile(tb, sz);
    >                 //would we rather have had ReadInFile throw here?
    >         }
    >
    >         if(!buf)
    >         {
    >                 //what do we do here, return or throw
    >                 return(NULL);   //ok, how about we let caller decide?
    >         }
    >
    >         tmp=Foo_ParseObjectFromBuffer(buf, sz);
    >         //now, what here?
    >         return(tmp);    //ok, return whatever we got.
    >
    > }
    >
    > and, in the caller:
    > SomeObjectType *Baz_TryLoadSomeData(char *name)
    > {
    >         char tb[256];
    >         SomeObjectType *tmp;
    >
    >         //see if we can load it as a ".foo" file.
    >         snprintf(tb, 256, "%s.foo", name);
    >         tmp=Foo_LoadSomeFileData(name);
    >         if(tmp)return(tmp);     //got something
    >
    >         //well, is is a ".bar" file?
    >         snprintf(tb, 256, "%s.bar", name);
    >         tmp=Bar_LoadSomeFileData(name);
    >         if(tmp)return(tmp);     //got something
    >
    >         ...
    >
    >         //ok, couldn't find anything, what now?
    >         //maybe?
    >         baz_errno=BAZ_COULDNTFINDFILE;
    >         return(NULL);
    >
    > }
    >
    > and so on...
    >


    First, I'm not sure why you felt the need to write out an example I
    already rebutted. Second, I'm not sure why you think badly written C
    code is justification for not using exceptions when writing C++.
    Third, yes, Foo_ReadInFile should thrown an exception if it cannot
    open the file or fails to read it in. Fourth, your example is
    horrible even if it were idiomatic C++. It would never serve as valid
    support for your position. It's too broken to be taken seriously.

    > a more concrete example:
    > consider we are trying to load a 3D model, but don't know in advance
    > what type of 3D model we are trying to load.
    >
    > or, we are trying to load a graphic image, but were not given the full
    > path or the file extension (it could be in one of several locations, or
    > a PNG, or a JPG, or a BMP, or a TGA, ...).


    You already mentioned this example (twice now!), and I already gave
    the rebuttal: There's no way for the open function to know whether
    this is what the caller is doing or not. The behavior of the caller
    generally has no bearing on whether a function should or should not
    throw an exception. This example is especially bad since it's no more
    code for the caller if they wish to retry with different arguments.

    >
    > sometimes, the graphic loading may itself be conditional, say:
    > did this texture have a normal-map image?
    > we know it didn't, if none could be loaded, but otherwise it is no big
    > deal (the texture is used without a normal-map).
    >


    So you suppress the exception in this case. BFD. That's considerably
    less common then when failure to open the file is fatal; or requires
    stack unwinding to prompt the user again, such as in a GUI where you
    must return to the event loop and wait for new input from the user.

    > an alternate scenario would be, say, if one particular branch of a
    > programs' drawing code depends on shaders, but the user's system doesn't
    > have shaders (say, because they have an old/crappy video card)?
    >
    > well, simplest option would just be to return an error (like, "hey, this
    > wont work"), with the application falling back to an alternate path:
    > "well, can we draw it without the shaders then?".
    >
    > <snip>
    >
    > the alternative strategy would be to always do things in the caller, like:
    > if(foo->DoWeHaveShaders())
    > {
    >         foo->DoItWithShaders();}else
    >
    > {
    >         foo->DoItWithoutShaders();
    >
    > }


    No, the simplest option is to ask the card at runtime if it has
    shaders and then select the code path as appropriate, using a virtual
    function and all of these other wonderful tools C++ gives you for
    selecting different function calls at runtime.

    > I say it depends on the situation.
    > and I am not saying that one doesn't use exceptions,
    >
    > I am not saying anything is universal rules here, but all depends on
    > whatever is more convenient at the moment.


    You said prefer error codes to exceptions with zero justification
    presented to your opinion. When pressed, your basic rebuttal seems to
    be that you're actually writing C and calling it C++ code. That is
    not saying 'all depends on whatever is more convenient at the moment.'

    > > Nonsense.  There's never a need to "detect[ing] 'well, that didn't
    > > work', without needing to be like 'on no, stuff has gone terribly
    > > wrong'."  This would be because the difference between the a retryable
    > > error and a fatal error is entirely in the hands of the calling code,
    > > not the called function. The response of the file open function should
    > > be the same in either case, because it has no clue what is
    > > appropriate.

    >
    > > You claim an catch block is inappropriate here, but you give no reason
    > > why.  I fail to see any reason why it is inappropriate whatsoever.  It
    > > doesn't even take up more space over if/else in your example.

    >
    > I disagree.


    There's nothing to disagree about, you can modify your code above and
    see it for yourself! It's not an arguable position. Exceptions serve
    actual users and your made up example better than error codes.

    >
    > trying things and seeing what works and what doesn't is actually fairly
    > common IME.


    And how does the open method know that's what the calling code is
    doing? How can that possibly justify the behavior of an open method?

    >
    > this is partly because some things are fairly common, like performing an
    > operation with only partial information, and the program may have to
    > probe around a little to figure out how exactly to go about doing it.
    >
    > >> often, if one is using an error code, the operation was probably just
    > >> handled as a no-op anyways.

    >
    > > Which is another reason why error codes are bad, there's a good chance
    > > the programmer will ignore them, leading to undefined behavior later
    > > on.

    >
    > only if the operation is likely to be critical for correct operation, in
    > which case one may need an exception.


    No, I think ignoring the value of malloc even for "optional" code will
    lead to undefined behavior. Ignoring a failure to open a file even
    for "optional" input files can lead to undefined behavior or crashes
    further down the road.

    >
    > many times, things are not critical, or may simply be a matter of
    > "Quality Of Experience" or similar, and even if the error code is
    > ignored, this may not actually be all that much of a problem (the error
    > code then being more like "did X go through successfully?" check).
    >
    > sometimes, the issue may even just be something like "the amount of work
    > to be done ran over the time limit, so we bailed out early", which would
    > unlikely hinder further operation.


    I have no idea what sort of situations you're imagining in your head,
    but these seems like the sort of situations that someone would like to
    know about.

    >
    > likewise for, say, "there were no more sound mixer channels available,
    > so the sound effect couldn't be played" (usually only happens if the
    > sound output is fairly noisy anyways, so the user is unlikely to notice
    > the missing sound effect).


    That's a pretty bad assumption--sound mixing is used for things other
    than audio playback in games. If I'm performing professional audio
    capture, then I care a lot if such an error occurs. In fact, I want
    to know about it before I start my recording session, if possible.

    > >> one can use an exception if the situation is sufficiently critical to
    > >> where the caller merely carrying on as before would not be a desirable
    > >> outcome.

    >
    > > Except it is generally impossible for the called function to know
    > > whether the caller wishes to carry on afterwards or not.  Hence why
    > > you should only return input that is useful to everyone and toss an
    > > exception otherwise.  People who wish to carry on can install catch
    > > blocks.  Everyone else gets precisely what they want.

    >
    > I still say, it depends.
    >
    > if they care, they may also check the return status, and if they don't
    > and something breaks, well, that may just be a problem which needs to be
    > fixed....


    The only way to find out if the problem needs to be fixed is to check
    the return code. To have any hope of correct operation, virtually
    every call must now check return codes, whereas with exceptions, only
    callers interested in "exceptional" behavior must do anything special.

    Just because you believe error codes can routinely be ignored doesn't
    actually make it true. Thus far, you haven't presented anything even
    remotely compelling to suggest that it is true. Looking at the C,
    POSIX, and Win32 APIs would suggest that most of the time, the error
    codes simply cannot be ignored and must be examined to ensure proper
    operation.

    > the other side of this coin is an uncaught exception which is prone to
    > blow up the application, which can be very annoying if it is due to
    > "silly little things which don't otherwise impact the apps' continued
    > functioning".


    Which is better than crashing due to undefined behavior due to an
    improperly ignored error and the resulting havok, such as data
    corruption. Given the choice between the two bugs, as a user, I'd pick
    the former over the latter any day.

    >> Which is exactly what exceptions accomplish! The fact that my code
    >> continued executing at the next statement means that the called
    >> function succeeded. It also means I never have to worry about
    >> "exceptional" conditions unless I can actually provide a meaningful
    >> response to the condition. If I cannot, then I can pretend that it
    >> does not exist and go on with my lives.


    >> This results in less code, and practically never more code, for the
    >> caller and called function. On that basis alone, exceptions are
    >> superior.


    > as noted elsewhere:
    > it depends on if the next statement actually depends on the prior
    > statement having succeeded.


    How is this an argument for error codes in the least? Again, you're
    simply not making sense at all, I have no clue how to even begin to
    interpret this statement.

    > >> it is usually done so to determine a success/failure status (so
    > >> that the caller logic can determine whether or not to try a different
    > >> option, ...).


    > > Or clean it's resources and manually unwind. Or just as likely,
    > > because that's so difficult to do manually, call abort() or a similar
    > > function to end the world.


    > "abort()" is often the worst option, from a "Quality Of Experience" POV,
    > as then the user has an app which simply dumps them back at the desktop
    > at the first sign of trouble, and even more annoying, "abort()" will
    > often not trap in the debugger either (unlike an uncaught exception).


    Yet there is tons of C code out there that does precisely that. GNU
    even recommends it as their default response in several situations:
    http://www.gnu.org/prep/standards/standards.html#Semantics

    If you think GNU is unique in this view, then you are quite sorely
    mistaken. You can go look at the source code for the various BSDs
    systems and see similar behavior too.

    Adam
     
    Adam Skutt, May 29, 2012
    #17
  18. mike3

    Rui Maciel Guest

    Luca Risolia wrote:

    > As a note, an "exception" does not necessarily represents a failure. For
    > example, you can throw an exception to jump out of a recursive search
    > algorithm when the searched value is found:


    Exceptions were developed explicitly to handle errors, as a way to to
    separate error-handling code from the program logic. Although they may work
    as a way to handle program logic, such as the case you pointed out, it isn't
    a particularly elegant use for them.


    Rui Maciel
     
    Rui Maciel, May 29, 2012
    #18
  19. mike3

    Luca Risolia Guest

    On 30/05/2012 00:04, Rui Maciel wrote:
    > Exceptions were developed explicitly to handle errors, as a way to to
    > separate error-handling code from the program logic. Although they may work
    > as a way to handle program logic, such as the case you pointed out, it isn't
    > a particularly elegant use for them.


    What is elegant is a matter of opinion. Exceptions are not intended to
    handle errors only, not according to authors like Stroustrup at least,
    from whom I deliberately took one of the corner cases. Of course you
    have to consider every case *cum grano salis*, I did not mean to say
    that exceptions should always be used to control the program logic:

    "Using exceptions as alternate returns can be an *elegant technique* for
    terminating search functions – especially highly recursive search
    functions such as a lookup in a tree."

    from paragraph 14.5, "Exceptions that are not errors" ("The C++ Prog.
    Language" 3rd ed.)
     
    Luca Risolia, May 29, 2012
    #19
  20. mike3

    Ian Collins Guest

    On 05/30/12 10:51 AM, Luca Risolia wrote:
    > On 30/05/2012 00:04, Rui Maciel wrote:
    >> Exceptions were developed explicitly to handle errors, as a way to to
    >> separate error-handling code from the program logic. Although they may work
    >> as a way to handle program logic, such as the case you pointed out, it isn't
    >> a particularly elegant use for them.

    >
    > What is elegant is a matter of opinion. Exceptions are not intended to
    > handle errors only, not according to authors like Stroustrup at least,
    > from whom I deliberately took one of the corner cases. Of course you
    > have to consider every case *cum grano salis*, I did not mean to say
    > that exceptions should always be used to control the program logic:
    >
    > "Using exceptions as alternate returns can be an *elegant technique* for
    > terminating search functions – especially highly recursive search
    > functions such as a lookup in a tree."
    >
    > from paragraph 14.5, "Exceptions that are not errors" ("The C++ Prog.
    > Language" 3rd ed.)


    Elegant maybe, but potentially very expensive if used injudiciously.

    --
    Ian Collins
     
    Ian Collins, May 30, 2012
    #20
    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. Greg  --
    Replies:
    4
    Views:
    2,180
  2. Shane Groff

    Exceptions vs. Error Codes

    Shane Groff, Oct 10, 2004, in forum: C++
    Replies:
    8
    Views:
    690
    Mike Wahler
    Oct 10, 2004
  3. Replies:
    2
    Views:
    2,854
    Malcolm
    Aug 20, 2005
  4. mike3
    Replies:
    14
    Views:
    613
  5. Allen
    Replies:
    1
    Views:
    662
    Mark Rae [MVP]
    Dec 3, 2007
Loading...

Share This Page