|
|
|
|
|
by wvenable
1752 days ago
|
|
Where you handle exceptions has nothing to do with where they are thrown. You put your try/catch around whatever operation can be retried at the top level. I don't know why you'd need to rewrap exceptions -- I've never done that. In that handler, you just need to know if the exception is fatal or a temporary issue for which retrying might succeed. If there was a CanRetry flag on the exception, that makes that determination easy without having to know every potential exception type. Your FileNotFoundException is a good counter-example as maybe the called code is unable to know the intent. So, yes, in that case the handler has to make this determination based on the type (as we do now) or some code in the middle, that knows the intent, needs to catch and set that flag. But most of the time one can determine at the point exception is thrown whether or not it's a potentially temporary situation (like a network error) or a unexpected fatal program logic error. Perhaps "CanRetry" is too prescriptive of a name. |
|
Funny you say this, when it's demonstrably NOT the case: a throwing method NOT wrapped in a try/catch will NOT have its exceptions handled at the call site. And vice-versa. If you want to retry a particular failing operation, you write try/catch around IT, not several levels up the stack.
You _could_ write it several levels up the stack IF you have precisely typed exceptions, therefore wrapping.
> I don't know why you'd need to rewrap exceptions -- I've never done that. [...] maybe the called code is unable to know the intent
To convey meaningful semantic information about the (business) operation that failed. Updating a record in the database can fail due to business rules (DB constraints), network connection that disappeared, concurrency conflict, transaction deadlock, etc. The user or higher-level code is not interested in the root cause, but in the actual consequence ("Could not update record". And yes, "IsRecoverable" flag, the value of which depends on the inner exception and its properties.).
And yes, the called code rarely knows the intent. There are a bunch of libraries out there being used in diverse contexts. So you catch and wrap the exception. Wrapping wouldn't be needed if library authors were careful about designing their exceptions, but I've rarely seen this to be the case. Even C# guidelines recommend you to use the generic, system-provided exceptions if an "appropriate one" exists. (IMO, a most terrible advice. And I discovered it was terrible by first following it then going back and designing "proper" exceptions for the system.)
> Your FileNotFoundException [...] needs to catch and set that flag.
But the exception type does not have that flag. So you have to wrap it in another exception. (Though all exceptions in C# have a Data field that is object -> object dictionary accessible to anyone. So you could use that.)
> You put your try/catch around whatever operation can be retried at the top level.
What is "top-level" for you? The shell's REPL loop? Exception blocks are non-restartable, so how would REPL continue the path-searching loop that threw FileNotFoundException?
> temporary situation (like a network error)
Ah yes, I love these. Someone pulled the power cable on some router the computer is indirectly connected to. To the program it looks the same as ordinary timeout error. How temporary is it?