1

I'm writing a library which will be a base for a turn-based battle system but i don't know what are the best practices for exception handling, has anybody some advice for me?

Should I catch every generic exceptions/ exceptions thrown by standard components (like lists,dictionaries,etc...) and then throw a contextualized exception?

If I have public method that throws an exception, when I call it from another library method should i catch the exception and then re-throw it? And if the method is private?

EDIT: I'm sorry I didn't mention that I throw exceptions only when there are some bugs

15
  • 1
    "I throw exceptions only when there are some bugs" You're in for some fun surprises. Apr 24, 2017 at 15:42
  • 3
    @TobiasKnauss what you describe is exactly the opposite of what is recommended in .net. Apr 24, 2017 at 21:09
  • 3
    @TobiasKnauss finally blocks are always needed, but exceptions within a library should not be caught unless they can be successfully handled (worked around entirely to achieve a correct solution). The only other reason for doing a catch is to transform the exception to a different type. Apr 24, 2017 at 21:18
  • 1
    Recommended reading: blogs.msdn.microsoft.com/ericlippert/2008/09/10/…
    – Mike
    Apr 24, 2017 at 23:45
  • 1
    @FrankHileman your answer wasn't downvoted because it linked to the doc, but because it only linked to a doc.
    – RubberDuck
    Apr 25, 2017 at 21:42

4 Answers 4

5

First, this will be an opinion, so many reasonable answers will be downvoted by those who have different opinions. Second, it will be somewhat language and platform dependent: an approach that should be slightly better but is incredibly clunky in the language is a bad approach.

The most important choice is to have an understandable plan and communicate it. You probably are thinking of these types of errors:

  • You called the library incorrectly and want to give you the correct error message. You might choose to "output the error message and crash" as this is a development time bug.
  • A dependency passed an error or responded incorrectly. For example, the GUI refuses to allocate colors. As you cannot handle it, just bubbling it upwards is fine.
  • An unusual return value occurred. It's an exceptional value, e.g., "creature cannot find route to target" or "route is too long" but still a known and valid return. Many languages work better if this bubbles up as an exception. The user of the library may choose what makes sense for the game.

I recommend you pick and document a naming scheme for problems so that a developer knows what type of exception is passed upwards.

3

Should I catch every generic exceptions/ exceptions thrown by standard components (like lists,dictionaries,etc...) and then throw a contextualized exception?

I've had good success with this approach, but be sure not to destroy the stack trace. You'll want your exception to have an InnerException (Java calls these a "Cause") that contains the original exception.

By wrapping standard lib exceptions in domain specific exceptions you gain some flexibility in implementation details without breaking API contracts. Let's say you allow an IndexOutOfBoundsException to bubble up out of your code and into the calling client. The client has no choice but to catch IndexOutOfBoundsException. Later, you switch from internally using an array to a list. Now the client code will be broken because the same error case throws an ElementNotFoundException. If you had wrapped it in an AwesomeLibException, your API would have remained intact and the client wouldn't have silently broken code when they upgraded versions of your library.


Now, some would argue that inner exceptions still result in a leaky abstraction. They're likely right, but by convention, inner exceptions are not part of the API contract and should not be inspected by client code. They're there to assist in debugging of the lib, not for the client code to inspect and handle directly.

3

There are many opinion based answers, but there is one answer which absolutely everyone should agree upon:

If your library throws an exception, the user must catch it to handle it. Thus, the user's opinion about how you should throw exceptions is the right one.

If your user is expected to wade deep into your implementation every time an exception occurs to figure out what went wrong and to handle it, you should throw the original exception. Now usually this is a silly assumption. Most users wont even have the source code to their libraries, much less the know how to debug them, but your program may be different. If your users have a good reason to dig deep into your library, wrapping the exceptions might simply get in their way. That being said, it's generally poor form to force the user to be aware of the implementation details of your library. Imagine if they had exception handling for an error you might make with a List, only to find out that you refactored the library to use arrays instead.

Another case might arise if your exceptions are really errors: exceptions that are never intended to be handled. They're intended to abort the application. Perhaps your exception in the algorithm using the List puts your library in an inconsistent state that can never be used again. I'd call that poor design, but there are plenty of non-code reasons to make strange products in the real world.

Myself, I prefer to treat the exception as a last ditch conversation with my user. It's where my library has failed to live up to its expectations, and I have to admit that things are going to be dicey. If so, I try to clean up as much as I can (try to get the system into a consistent state), and then throw a customized exception that they can try to catch and recover from. If there's a chance your users might want to wade deep into your library, make sure you give them the InnerException to preserve the stack trace and exception information they need to do that.

But in all cases, your user's opinion is key. Make a product that your users will want to use, and the rest can always be sorted out later. Make a perfect product that your users won't use, and it doesn't matter how perfectly you followed best practices.

-3

It always depends on what you going to do further with your caught exceptions.

Speaking from a code-maintenance and DRY point of view, it is advisable to have like a global exception handler, at the top level of you application. For example: Global.asax.

Start from that point, you can then persist exceptions and errors to the database in order to inspect and fix them some other time and also make sure that your user sees a nice formatted error page instead of the default exception page.

2
  • 5
    The asker is implementing a library, not an application, so it doesn't make sense for them to implement a top-level exception handler, log to a database, or display an error page. Apr 24, 2017 at 11:28
  • 2
    Additionally suggesting Global.asax is completely nonsensical for everyone not doing web development. Apr 24, 2017 at 15:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.