A big argument for using systems programming languages is thay they are fast: you are writing code that is compiled once and run thousands of times per second on millions of computers. Why would I care so much about compile-time performance? If I need a faster compiler mode during development (though in my experience, the pain of C++ compile times is due to its muti-stage transformation and lack of separate compilation for templates, not its exception handling... I don't find my projects that turn off exceptions to compile much faster), the compiler can also implement a really slow mechanism for exceptions as an alternative.
I also maintain that requiring the developer to do manual error propagation to get errors from the point of failure to the point of reporting to the administrator or the operator (which is what happens to almost all errors, whether you are writing a command line tool, a graphical application, or a website) is "boilerplate". At the simplest, without changing the error model, littering the code with calls to try! that push the error upwards is automatable (and I have a friend working on a compiler plugin to accomplish exactly that).
An example: I like statically-typed languages, but as demonstrated by languages with type infererence, having to declare every type every time it is used is "boilerplate", especially if types are long and unwieldy. C++98 has typedef, which lets me take C++'s long and unwieldy type definitions and make them shorter. If you are used to typing them out manually, every single time, some might even claim this is "ergonomic". However, C++11's auto is much better, and as demonstrated by languages like OCaml and Haskell even that isn't as good as it can get. C and Go have long and unwieldy error propagation (checking flags and manually returning new ones). Rust provides macros and tooling for this that make it safer (no more "goto fail;" or "Rage Against the Cage" exploits) and easier (like typedef!), but that doesn't mean it isn't still "boilerplate".
I mean, sure. But I've personally benchmarked a lot of code that uses Result and noted where it caused performance issues, if it did, fixed the code so it didn't anymore, and moved on with my life. Most of the time, it wasn't even close to being a bottleneck--most of the time the branch is correctly predicted and the time is just spent copying bytes for the `Ok` value, which is basically a nonissue if you can keep your error word-sized unless you're calling a tiny function in a tight loop that LLVM can't inline for some reason. OTOH, landing pad generation in Rust probably doubles its compile time, which is already pretty slow (which is one reason I personally will probably just compile with panic! -> abort, when that option becomes available).
I don't consider the error handling boilerplate because I do frequently want to recover, even from supposedly fatal errors. For example, if I'm handling an iterator of things, and some of them fail, I still usually want to keep processing them before I return the error. Exceptions lock you into a very rigid pattern of error reporting that make that much more difficult to deal with. Because libraries don't assume that I want to fail when they do, it can be easy and fast for me to do this, even for pathological inputs; that wouldn't be the case if everyone used exceptions.
I agree with you that Rust could do better at providing options for error reporting with panic. I believe there's an RFC about that right now, please comment on it!
I have been a games developer in a past life (my primary focus for over three years), and I am unconvinced I or any of the other people I worked with would have been willing to tolerate a low-grade performance degradation distributed around all of our code if we had access to programming languages that did not have that issue and weren't infinitely worse (and while I really wish I could use Rust, it just isn't infinitely better in a way that seems relevant for either the hardcore or casual gaming markets). Also, it sounds like there is something wrong with the Rust compiler if this landing pad generation really doubles the compile time... a poor compiler should not influence the language design in such a negative direction.
Solving problems like your iterator issue should not be difficult with exceptions: in fact, frankly, I don't see why it is any harder than with Result: your worst case is that you start with a primitive, "antitry!" (which should be called "try!", as it makes more sense than what "try!" currently does for that word) which performs an operation and returns a Result of either its value or its failure. Even if you do this "frequently", I would be shocked if this was remotely as common as the code that was assuming success and just wanted to fail if something fails. And, as long as you aren't trying to "handle" those errors (and it doesn't sound like you are, you just kind of want to fail out with a list of failure reasons) there is no semantic complexity either. Exceptions are the flexible primitive, not Result: simulating Result from exceptions requires a tiny finite amount of code, while simulating exceptions using Result requires modifications to an arbitrarily large amount of code.
As for fixing panic, what really sucks is that so much library code is going to be written using Result now when much of it should have been written with panic, both in the core library and from third-party developers, meaning that the boilerplate is going to be somewhat inescapable at the lowest levels of the program... I think the thing I like most about programming in Python vs C++ is that I don't have to wrap every single API I use to make it handle errors in a sane way. I don't think that fixing panic at some point in the future is going to work as there seems to be such awkward community momentum against exceptions and behind Result, when the real RFC needs to be "when you write your library, try to use panic, not Result".
> Also, it sounds like there is something wrong with the Rust compiler if this landing pad generation really doubles the compile time... a poor compiler should not influence the language design in such a negative direction.
Um, actual, non-trollish question: do you know how exceptions are implemented? Because I can't think of a way around this in a language with destructors, short of some sort of "doesn't throw" effect (which Rust doesn't currently have) or aborting on every exception. Do you have any pointers? Similarly, I don't understand how your "antitry" solution would be efficient on pathological input--"zero-cost" exceptions are far from that when the exceptions actually happen (and can be made to happen by malicious users). You also haven't addressed how I'm supposed to know to use antitry in the first place, which is one of my biggest issues with unchecked exceptions--again, the only alternative I see is a "throws" effect. All of these are language level concerns, not implementation-level ones.
> Exceptions are the flexible primitive, not Result
Catchable exceptions require coding transactionally if you want to use them everywhere and maintain strong exception safey. There's an enormous cost associated with that too; and worse, it can't be checked by the compiler.
Again: I have actually benchmarked a lot of code that uses Result, explicitly checking to see if it was a performance issue. It's almost never a performance issue. So performance-related arguments for why exceptions should be used everywhere are going to fall on deaf ears here. I am far more interested in seeing whether we can eliminate panics altogether for most of the common cases (e.g. with compile-time checked range types).