Almost everything else you listed represents a bug in your software that should terminate execution.
I’m more than a little shocked that you think yeeting exceptions up the call stack is appropriate for these cases.
Almost everything else you listed represents a bug in your software that should terminate execution.
I’m more than a little shocked that you think yeeting exceptions up the call stack is appropriate for these cases.
Not necessarily. You should only handle expected conditions locally if there is a specific action that you need to take in response to them -- for example, correcting the condition that caused the error, retrying, falling back to an alternative, or cleaning up before reporting failure. Even if you do know what all the different failure modes are, you will only need to do this in a minority of cases, and those will be determined by your user stories, your acceptance criteria, your business priorities and your budgetary constraints. That is what I mean by "expected conditions." Ones that are (or that in theory could be) called out on your Jira tickets or your specification documents.
For anything else, the correct course of action is to assume that your own method is not able to fulfil its contract and to report that particular fact to its caller. Which is what "yeeting exceptions up the call stack" actually does.
> Almost everything else you listed represents a bug in your software that should terminate execution.
Well of course it represents a bug in your software, but you most certainly do not terminate execution altogether. You perform any cleanup that may be necessary, you record an event in your error log, and you show a generic error message to whoever needs to know about it, whether that be the end user or your support team.
Again, what action you need to do in these cases will depend on your user stories, your acceptance criteria, your business priorities and your budgetary constraints. But it is usually done right at the top level of your code in a single location. That is why "yeeting exceptions up the call stack" is appropriate for these cases.
You only terminate execution altogether if your process is so deeply diseased that for it to continue would cause even more damage. For example, memory corruption or failures of safety-critical systems.
> I’m more than a little shocked that you think yeeting exceptions up the call stack is appropriate for these cases.
I hope I've clarified what "yeeting exceptions up the call stack" actually does.
The alternative to "yeeting exceptions up the call stack" when you don't have any specific cleanup or corrective action that you can do is to continue execution regardless. This is almost never the correct thing to do as it means your code is running under assumptions that are incorrect. And that is a recipe for data corruption and all sorts of other nasties.
You can only assume that the methods you have called have left their own work in a consistent state despite having thrown an exception. If they haven't, then they themselves have bugs and the appropriate cleanup code needs to be added there. Or, if it's a third party library, you should file a bug report or pull request with their maintainers.
You don't try to clean up other people's work for them. That would just cause confusion and result in messy, tightly coupled code that is hard to understand and reason about.
var myFile = File.Open(filename);
try {
while ((var s = file.ReadLine()) != null) {
var entity = ProcessLine(s);
// do whatever you need to do to entity
}
}
finally {
myFile.Dispose();
}
C# gives you the using keyword as syntactic sugar for this: using (var myFile = File.Open(filename)) {
while ((var s = file.ReadLine()) != null) {
ProcessLine(s);
// do whatever you need to do to entity
}
}It's certainly far, far better than having to add exactly the same check after every method call. Which is only what you need to do if you're working in a situation where exceptions are not an option.
As a bonus, you can’t accidentally fail to catch an exception, and you can model much more complex error handling than just ”catch and raise.”
For example, it’s trivial to implement error recovery, where you implicitly collect all errors that occurred and then can report them once at the end.