>No, that is the entire point of exceptions

Which is why they're bad design. The comparison to function calls is misleading :

- Function calls are named, given a function name you can always go to a function definition and see for yourself how many functions it calls in all return paths. You don't have to, but you can, and this is crucial in many many situations, not the least of which is debugging (e.g "oh no! program ran into infinite loop, What was the last function called? I will go and see its definition")

- Function calls can be statically type-checked, given a function that returns X type, the compiler will ensure that every reference that holds its return result is X or one of its subtypes.

But in exceptions :

- Catches (the equivalent of calls) are unnamed, the set of places a catch can catch from is exponential in the number of function calls in its try{...} block. For an example, if you want to debug given a catch, you must recursively inspect every single function call in the try{...} block to know which function threw the exception. And no, the 50-line stack traces don't make things any better, if any thing they just rub in the fact of how many functions you need to inspect to know where the problem came from.

- Throws are not statically type-checked, given a function that throws E1, the compiler will not bother to ensure that it is called in contexts where E1 is caught, you're completely on your own. It is this which makes Exceptions free program-crashing coupons. Only Java tried to solve this as far as I know, and the solution is still full of holes.

>I'm sure they would, just as they would be horrified by having multiple returns in the same function - never mind horrors like "break" and "continue".

You say this tongue-in-cheek, but as a matter of fact plenty of imperative languages ban "break" and "continue" for exactly this reasons, they are a huge source of loop bugs, and many style guide have problems with multiple returns and regulate them heavily if not banning them outright.

Regardless, the comparison is disingenuous, I just spent ~1000 words or so arguing why Exceptions are so utterly and fundamentally different from ordinary control flow. No return statement unwinds the stack arbitrarily, possibly to its very end, and with absolutely 0 static gaurantees.

If you think this is okay, we won't reach any useful consensus, and that's okay. But your original claim that Joel engages in faulty reasoning when he rejects exceptions as a form of goto is wrong, there is very good reasoning why exceptions are actually a much more dangerous goto than most modern goto, and plenty of much smarter people than you or me (or Joel) follow and accept this reasoning. Those people include those responsible for some of the most safety- and\or performance- critical software, like games and operating systems.

>Dijkstras problem with goto was not that they jumped to a different place in the progam,

I read Dijkstra's paper, and I'm pretty sure when I say his problem was in fact exactly that. Unrestricted gotos make control flow an arbitrarily-complex graph, the fundamental reason for this is that the jump labels are public, and exceptions share that in a way that nothing else does, their catches are public to every single throw beneath them in the call stack. Throws are gotos that search for their labels at runtime, possibly failing and crashing the program or unwinding it beyond recognition.