4 ms·
> For example, if foo() calls bar() and baz(), which each throw 3 different exception types, then now foo() might throw 6 different exception types. > I think
by jdmichal 7y ago
> For example, if foo() calls bar() and baz(), which each throw 3 different exception types, then now foo() might throw 6 different exception types.
> I think it's fairly common to bulldoze all that complexity by declaring a function that just "throws Exception".
These are both solved by the same approach: foo should be wrapping those underlying exceptions under its own domain, not just passing them along. This has the added bonus that the further up the call stack you go, generally the more context you have about the operation. So you also get to set a new message that explains that context. So foo should only throw FooException, which might be wrapping an underlying BarException, which might be wrapping an underlying BazException. You get a full accounting of what happened, and how each layer interpreted it.
For example: I invoke the user preferences subsystem to give me the user's foo setting. User preferences can be in a flat file or an embedded database. If I don't wrap exceptions, now my user preference system has to expose that implementation detail by exposing both file and database exception types. Instead I should wrap both of them in a UserPreferenceLoadingException type or whatever makes sense.