3 ms·
TryParse is a hack around exception performance. In fact, all the TryXXX things usually are. It's purely an unfortunate hardware/performance decision that impac
by MichaelGG 12y ago
TryParse is a hack around exception performance. In fact, all the TryXXX things usually are. It's purely an unfortunate hardware/performance decision that impacts library design. In F#, I'm happy to write:
let i = try int s with _ -> -1
OCaml does some similar things, I think. You might use it to attempt to get an item from a dictionary, and return a default if not found. It's easy and elegant.
Saying "exceptions are for exceptional cases" is meaningless wordplay. Call them faults, traps, errjumps, whatever and it breaks down (faults are for faulty cases?). Library design should trump all, and sometimes the better way is to throw in many cases.
- barrkel 12y agoNo, it's more than that. Exceptions are a useful signal that something has gone wrong with the application. If you can get into that mode of thinking, other benefits flow out of it. You don't get in the habit of catching low down in the stack unless it's a deliberate retry mechanism. You can rely on your debugger breaking on exception meaning something, rather than having to set detailed and careful exception breakpoints. When you use exceptions as a glorified alternative function return value, you risk creating accidentally broad exception firewalls - if you don't catch just the right subset of exceptions, you start swallowing genuine errors. My advocacy of exceptions for exceptional situations is a cultural one, and the primary aim of the culture is so that you don't catch exceptions. You should almost never catch them. They should almost always bubble up. Only the server handler dispatch or UI event loop should catch, most of the time. And you can only make that work if the library doesn't throw exceptions for situations where you are likely to want to handle them. I tend to think of errors as falling into three classifications: (1) incorrect user input, (2) unexpected external condition revealed through a system call, and (3) programming error. You almost never want to catch (3) - null pointer exceptions, overflow, division by zero, index out of bounds, etc. In some apps, you probably want to terminate. You don't want to catch the exception, you don't want to catch, wrap and throw the exception, because these just obscure the nature of the problem. You might occasionally want to catch (2) to perform a retry or use an alternative strategy. Depending on how expected the error is, it might make sense to have two different styles of invoking the operation, one that throws, one that doesn't throw. Some code just cares about the happy path and doesn't mind blowing up on failure, other code needs to try harder. But (1), user error, requires design. It means the user - normally the guy who, however indirectly, is paying for the code - has made a mistake, and that's probably our fault; we didn't do enough communication. We need to work hard to correct it. Exceptions come with technical messages. Technical messages are not user friendly. Throwing an exception would just mean we'd have to catch and translate it. It creates work. It doesn't help. Transporting the message up the stack automatically doesn't help either; context that could communicate the problem to the user is lost. Exceptions simply aren't the right tool. The affordances are wrong, automatic unwind is wrong, and the instincts they inculcate about catching, break everything else.
- charlieflowers 12y agoYeah, this is interesting. Exceptions come with 2 different moral guidelines that actually contradict each other. The contradiction is not obvious on the surface: (1) Exceptions can make your contract with your calling code nicer by offering an alternative way of unrolling the call stack. That way, your caller can deal with anything unexpected in a more convenient way. (2) But the price of being able to do so is expensive. The whole system is designed and optimized for "normal" procedure calls making normal procedure calls and returning normally. Exceptions go against that grain and are very expensive. So only use them for "truly exceptional" situations. The problem is, if you try to take advantage of #1, you run afoul of # 2. TryParse vs Parse is a perfect example. The calling contract of Parse is so much cleaner because it takes advantage of # 1. But having an exception occur is too heavy because it runs afoul of # 2. Problem is, an exception is almost _always_ too heavy. So it is an illusion (delusion) to think you can ever freely enjoy the benefits of # 1. If you need a guideline like # 2 at all, then # 1 is a lie.