...I wanted to find the source before writing this Q, sadly I couldn't.
My mental model was that exceptions were thought as an alternative to returning error codes from a function, which is the C way to signalize failure. Returning error codes and managing them is error-prone, cumbersome and tedious; which is why a more right-handed mechanism was thought.
Problem is, then I started reading and hearing opinions that abusing exceptions is bad. Well of course - if I want to see if an array contains element X then it would probably not be a good idea to assume it does and then throw and almost immediatelly catch an exception if it doesn't.
But these opinions were more strict than that. An example of an improper use of exceptions was if, for example, we have a web app and a user requests something that is not there / sends invalid data / any other condition arises that requires displaying an error page to the user. In this case, I was told, it would be a bad practice to throw an exception deep down in the server code, catch it before the request stops being processed and then display an error page.
If I understand this mentality correctly (which doesn't have to be the case), the justification was that, since throwing the exception is not intended to crash an app (the situation is recoverable), then the situation is "sensible business-wise"; while exceptions should be reserved for situations "insensible business-wise", which I suppose means "unrecoverable"? But this seems to imply that if the app can continue and is not supposed to crash, I should not throw exceptions; I should only throw if the app cannot continue and must crash.
Is this commonly agreed upon? If so, then why?
I have feeling this is supposed to apply to almost all programming languages (but, notably, not Python.)
I must admit in my anti-pattern ridden game I do otherwise. For example, when the user sends a JSON with a team, I obviously must validate this data. I seem to be doing precisely what is condemned above: I pass the JSON data to the pieces of code that are responsible for validating it and, if it's valid, constructing an instantiation of the
Team class. If the data is invalid, an exception is thrown. I thought this would be convenient for me, especially since this seems to mix well with C# facilities I use to construct the team: for example, to instantiate a
Monster subclass from a monster name present in the JSON, I use
Activator.CreateInstance which naturally throws if the monster name present in the JSON doesn't match any subclass of
But, well, others are more experienced than me, I marked this with a TODO that I should refactor this to
if(isValid(teamJson)) team = new Team(teamJson) even though I don't understand why and even thought I don't like this idea because
isValid() would have to share a lot of code with the
Yesterday, however, I read something surprising: Throwing exceptions on assertion failures is, generally, a bad idea, because assertion failure should crash the program while an exception can be caught*. This seems to go against the mentality I presented above, which would assert that exceptions should be thrown precisely when the program must crash.
Could you clear my confusion? When should exceptions be thrown? In particular, should exceptions be thrown then and only then when the program should crash?
*(Yes, this applies to C++ while remarks about my game were about C#; but again - I don't want to discuss language facilities of this or other language, but when exceptions should be thrown in general, which - again - is AFAIK language-agnostic, although with few exceptions like Python.)