> The problem with "Use Exceptions for Exceptional Problems" is that it avoids ever defining "exceptional". Usually, it is then interpreted to mean "couldn't be predicted".
Huh? No. "Exceptional problems" are ones where the only thing that the code does is report the error. Whether a problem is exceptional is dependent on whether or not it's part of the normal workflow.
This is why there are, for example, 2 integer parsing methods in many languages, one that returns false for strings that aren't integers and one that throws an exception. It's up to the user of the function whether they have a way to handle the exception or whether they just want to report it to the user and exit.
> My rule of thumb is to use an exception whenever the function cannot complete its contract.
Exceptions that a function might throw are part of its contract.
> If I have a function LogIn(username, password), I expect to be logged in after the function completes.
That's a terrible design. You've violated a ton of different principles: single responsibility principle being the biggest.
For this I would have something like `authorize(username, password)` that figures out whether the username/password is valid, and then `login()` that actually creates the session. I might have another function `tryLogin(username, password)` that tries to login and returns some error info on failure.
In your system, what happens when a login happens and slips past your exception handler because it's used in a place that you didn't expect it to be used, and there's no type checking on exceptions? You just let the whole system go down. What happens when you want to log in with an auth token instead of a username/password? Have fun separating out your session logic. What happens when you want to write stress tests against your login system and now have to piece together a test suite that covers all cases for a monolith because you don't have any units to unit test? You rewrite the whole thing is what happens.
> Anything that trickles back up to the user and is displayed as an error message will have lag based on the user's reading speed.
Or it will cause lag for your entire server because wrong logins are fucking your stack and therefore your garbage collection.