2

I have a very basic library that serves the purpose of collecting some useful but simple pieces of code. Like for example a Percent struct or functions like ToDegrees() and ToRadians(), just to give an idea.

I caught myself declaring custom exceptions that aren't used inside that library. For example a MultipleDispatchException when implementing multiple dispatch with dynamic keyword. Then intention is to throw this exception instead of the ObjectNotFoundException of the example. The "smell" is that this library does not have any multiple dispatch code so it doesn't throw this exception neither catches it.

The closest thing that I could find was this question in stackoverflow about Organizing Custom Exceptions in C# without any useful answers while the commentators focus on the OP's decision to make the exception an inner class. Now if that was a private project I wouldn't care any less, I would move on and simply follow the "ship the damned thing" principle and perhaps worry for that later. But I intend to open source this library and in my mind this library should be relative to a broader audience and not just my own projects.

Is there some common practice for that case or some pitfall that I can't see?

5
  • Sometimes all of the exceptions that are thrown by an application are placed in a single assembly whose only purpose is to define them. This is also an excellent place to add comments explaining what the exceptions "mean" and under what conditions they might be thrown. And I don't have to look all over the source-code to find the definitions . . . Feb 14, 2021 at 17:51
  • If it's a "collection of useful pieces of code" then I don't see the problem. Surely your library has tons of stuff in it, which is not used elsewhere! I mean, does your library need to convert degrees to radians? If not, then why does it have ToRadians?
    – user253751
    Feb 16, 2021 at 15:59
  • @MikeRobinson I read your other comment although now (unfortunately) deleted. I've raised my concern in meta if you are interested in a follow up. Feb 17, 2021 at 0:30
  • @user253751 you have a valid point. The thing is that with "regular" code you can see the intent even without documentation. With a XyzException is not immediately clear just by looking at the exception code. Feb 17, 2021 at 0:39
  • @SteliosAdamantidis well then write better documentation for it?
    – user253751
    Feb 17, 2021 at 10:53

4 Answers 4

4

There is nothing wrong in placing custom exception classes in a library for the sole purpose of reusage (whereelse should they be placed if they are required by more than one assembly)?. What I think is debatable is placing other things in that library as well, things which have nothing to do with those exceptions. So why not place the exceptions in a library of their own?

That would avoid coupling components together artificially which don't need to be coupled. Making two libraries (or more) instead of just one follows basically the idea of the Interface Segregation Principle, on the abstraction level of libraries instead of classes.

Of course, sometimes there are practical reasons why you want to place exception classes in an already existing library instead of creating a new one. This could be motivated by easier deployment, bundling things under one name, less configuration management overhead for an extra library, decreased compile times, or similar reasons. You have to decide by yourself if these reasons may be relevant for your case.

3
  • That's very much my thought, "Doc." When an application defines custom classes that are, of course, used throughout the application, I very much like to find those definitions in just one file which everyone can then include. "Who cares if they actually use them – at least they're all singing from the same hymnbook." The compiler already knows how to ignore anything that isn't being used. "I have only one file that I have to 'include everywhere.'" Feb 15, 2021 at 1:07
  • @MikeRobinson: I assume you have C or C++ in mind? Then one has to be very careful with this strategy - putting a lot of unrelated things into one lib does not scale well with the program's size. For smaller programs, this is fine. For larger programs, this is ok if those custom classes are really supposed almost everywhere throughout the application, otherwise increased turnaround times might kill any productivity.
    – Doc Brown
    Feb 15, 2021 at 6:45
  • The reason to put so many things in one library is that having too many libraries creates overhead of its own!
    – user253751
    Feb 16, 2021 at 16:00
1

I have a very basic library that serves the purpose of collecting some useful but simple pieces of code. Like for example a Percent struct or functions like ToDegrees() and ToRadians(), just to give an idea.

This sounds very much like it's a toolbox, and there's no inherent requirement of a toolbox using its own tools. That's the short answer. More elaboration below.


Library types

Libraries come in all shapes and sizes. I tend to make three distinctions here:

  • Toolboxes are not fully fleshed-out libraries with features, they're more of a grab bag of prebuilt classes/structures made for the consumer's convenience. They tend to contain more things than any one consumer would ever use, it's just easy to lump them all together in one thematic bag. Good examples here are System.Math and any Contracts-style project which contains DTOs but no real logic.
  • Frameworks are libraries that you build your code against. They contain an incomplete architecture, and you as the consumer are expected to write the complement to make it a whole feature. Think of it like a body with an amputated limb. To make the person whole again, you have to custom-build them a prosthetic. This prosthetic is unique to them, and you cannot just give it to someone else. It wouldn't fit. A good example here is Entity Framework.
  • Libraries are ambiguously used to refer to either the set of all libraries (including frameworks and toolboxes) or the set of libraries which are not framework or toolboxes. I tend to pick the latter.

Is this a hard and fast rule? No. Some libraries are even quite hard to classify, and some people strongly disagree with others on both the distinction and what that distinction means.


Using library content

The reason I make these distinctions, and why I mention them here, is because things are different between these types. What is acceptable for one is less acceptable for another.

For your question specifically, if your library satisfies the "toolbox" descriptor, then it is perfectly fine for it to contain classes (such as your exception) which are not yet used; because a toolbox' job is not to use its own tools.
Comparatively, if it's a library, I would say that the unused exception is out of place there, since libraries tend to contain a fully working feature (which implies that all of its parts are present purely because they perform a duty in the library).

For completion's sake:

  • Toolboxes tend to present a loose set of items that are not yet woven into each other. Some of a toolbox' content could be wholly unused and completely unrelated to other content.
  • Libraries tend to bring a completed feature with them. Here, you expect the library's content to all belong to the same cohesive construct.
  • To reuse the amputee analogy, a non-framework library represents the prosthetic rather than the person. As the person, if you were able to choose how to amputate yourself, you'd do it in a way that means you can use most (if not all) available prosthetic limbs. In coding terms, your codebase should therefore abstract its dependency on a library, so that tomorrow you're able to swap it out for a new limb without needing to change your main body.
  • Because frameworks provide an incomplete package and expect you to finish it, even though I do agree that general libraries should be abstracted so that they can be swapped out when needed, frameworks (almost by definition) are unbearably hard or even impossible to cleanly abstract, because they have (partially) driven the design of your architecture. This is why I've stopped trying to abstract Entity Framework in most projects because I find it an inefficient use of my time. The effort needed to pre-emptively abstract it vastly outweighs the likelihood that I'll ever swap it out. It's a calculated risk-benefit analysis.
0

Your library seems to be something like a utilities collection, with elements that might come in handy for some of your users' tasks.

When including an exception class in such a library, I can see two different motivations:

  • The exception class is used in other parts of the library (and then it's mandatory to either include the class or declare a dependency to some other library containing that class).
  • The exception class in itself is useful, either by offering specific functionality not found in basic exception types, or by merely proposing a standard type to be used for exceptional situations around e.g. multiple dispatch.

The first motivation doesn't apply to your case. So, include the exception class in your library if you're confident that it, by itself, adds value to the library, so your users are inclined to prefer this exception class over any basic one.

As with all utilities collections, there's still the granularity decision:

  • Packing everything into one library can easily lead to a monster, especially if you have dependencies on external libs. If your users only want one class from your lib, they still get the whole library plus dependency graph.
  • Splitting the library up can create a dependency graph of its own, with all the complexities involved, but it might well be worth doing so from the beginning, as later on it might be hard to split up a big monolith into pieces.
-1

The purpose of exceptions is to be able to propagate errors far from where they happen, so handling them later.

This could be useful for example in a library, where you will want the calling program to define what to do with every error.

But among the library itself, most of the time it doesn't matter. You will want to handle errors as soon as possible, in a procedural way rather than by using exceptions.

2
  • 1
    This doesn't really answer the question. It argues avoiding exception in favor of handling, but it doesn't address the validity of the existence of exceptions that aren't (yet) being thrown.
    – Flater
    Feb 16, 2021 at 10:03
  • I shall digress. Feb 17, 2021 at 16:31

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.