4 ms·
Exceptions are much worse than “goto”, in my experience. “throw” is basically a dynamically bound “return” statement—it’s hard to reason about where you’ll end
by evincarofautumn 10y ago
Exceptions are much worse than “goto”, in my experience. “throw” is basically a dynamically bound “return” statement—it’s hard to reason about where you’ll end up, because it depends on the call stack above you, and the type of object you decided to throw. The same throw site might jump to many different, unrelated parts of the program. Real exception safety is almost as hard to get right as concurrency, and for similar reasons.
- adamnemecek 10y agoI was referring to old school gotos, not like those in c. But yeah, we are in the same page.
- slezyr 10y ago> Real exception safety is almost as hard to get right as concurrency, and for similar reasons It's even harder to get right concurrency with exceptions :D
- quotemstr 10y ago> It's even harder to get right concurrency with exceptions No it isn't.
- Chris_Newton 10y agoI can’t help noticing that much of your objection applies just as much to return as to throw. Isn’t the point, in both cases, that you shouldn’t need to reason about where you’ll end up? Either your function can complete its task successfully, in which case it satisfies whatever invariants are required of it and returns accordingly, or it can’t, in which case it can throw an exception to indicate that inability to return successfully. In the success case, the calling code can then continue based on whatever returned value and/or side effects the function was supposed to provide. In the failure case, the calling code may well fail itself if it can also no longer complete its task successfully, and so on up the stack until you reach a level in your design that knows how to recover from the failure or stop the entire program gracefully, which is where you catch the exception. I’ve never quite understood the idea that exceptions are similar to goto. Other than transferring control over potentially long “distances” within a program, they don’t seem to have much in common at all. To me, a much closer analogy would be returning early from a function on success, if you reach a point in your algorithm where you already know the required answer to whatever question your calling code was asking. Another similar situation would be using a break or continue statement to finish an iteration early within a loop, or adding extra guard cases to stop a recursion early, again if you already know the outcome and continuing with the full algorithm has no advantage.
- evincarofautumn 10y ago> I can’t help noticing that much of your objection applies just as much to return as to throw. Isn’t the point, in both cases, that you shouldn’t need to reason about where you’ll end up? That is the point, but my specific objection is to the dynamic binding and dynamic typing, not the returning. With “return”, even early return, you don’t really need to reason about where you’ll end up at all—it’s always the end of the current function. And the same goes for functions that throw exceptions directly. The problem is that when you have unchecked exceptions, any function can throw, so every function call in your code is now also a potential early return, and for correct code you need to account for that.
- pjc50 10y agoThe real failure is that return types must be declared by exceptions need not be and generally aren't. So an exception can come teleporting through any part of your code. You can no longer enforce single return style, because any expression can return. This means that writing state-modifying code becomes unreasonably difficult, as you can no longer just write: // A and B must be kept in sync and updated together A = computeA() B = computeB() .. because it's possible that computeB() throws an exception, leaving the two out of sync. Yes, there are ways round this involving temporary variables. So you write: tmpA = computeA() tmpB = computeB() A = tmpA, B = tmpB; and home that neither an optimiser nor an intern removes the tmp variables. But wait! This still doesn't work, because your evil coworker has defined operator= on B to throw an exception! Personally I don't think that exceptions work very well in the presence of mutable state. Without mutable state, they're exactly equivalent to
- konstmonst 10y agoYou are just using the worng pattern. Use Computation a; Computation b; use(a, b); Then if the computation aborts in b, then computation a will be cleaned up as intended.
- pjc50 10y agoMy second point is that with exceptions you can't guarantee the assignment of two objects, because the assignment operator can throw.