In any case, panics are not guaranteed to unwind or be catchable: they can be turned into aborts (yes, on the stable compiler). This means an arbitrary library using them for recoverable error handling is incorrect.
A WITH clause mechanism implies no dynamism.
Please be more specific with your complaints. Thanks.
Additionally, unless one is using explicitly typed exceptions (i.e. Java-style checked exceptions, very much unlike Python), it requires allocations, as it's not possible to statically determine the size of the error object to be returned.
Similarly, from an assurance/reliability point of view, the dynamically typed nature of non-checked exceptions is unfortunate.
(These second two are, I believe, the points I made last time we discussed Python's exceptions.)
"We'll also need a way to handle out-of-memory (OOM) conditions. The standard library calls the abort intrinsic, which just calls an illegal instruction to crash the whole program. The reason we abort and don't panic is because unwinding can cause allocations to happen, and that seems like a bad thing to do when your allocator just came back with "hey I don't have any more memory"."[1]
Allocating is definitely a big deal for a pervasive error handling! For instance, parsing a number might not succeed. Both the actual parsing and the failure cases are cheap, but not if the latter has to be indicated by allocating and unwinding and doing a pile of the dynamic checks up the stack.
Additionally, whether the language is able to operate in OOM isn't the only reason to choose an error handling scheme. However, even if it was, I don't think it applies directly to Rust: Rust-the-language (and Rust-the-core-library) can operate in an OOM condition, e.g. people run Rust code without needing a dynamic allocator at all. You are correct that some parts of the standard library don't handle OOM, but, using exceptions pervasively means that there is one error handling scheme for things that can rely on having an OS/malloc and one for things that don't need them.
> Besides, unwinding already causes allocation
Yes, and that is one reason why unwinding is not used as a pervasive error handling scheme in Rust: there are various fairly fundamental problems with it. It is one of the reasons why panics can be switched to abort.
Exceptions are not meant for "pervasive error", they are for exceptional execution paths. If an execution path is frequent enough, wether it's an "error" or not, then it should not be an exception.
I think this is the part of the argument that the "no exception camp" usually misses : there are multi type of errors (recoverable vs fatal, frequent vs unfrequent, expected vs unexpected), having exception is not about using exceptions for all of them
Go also backed into adding most of the machinery for exceptions by adding catch with unwind for panics. If you're going to have the unwinding machinery, why not have real exceptions?
Exceptions aren't so bad if you do them the way Python does, using a predefined exception hierarchy. Catching an exception catches everything in its subtree. Catching RuntimeError catches most of the things one can induce from outside the program. Python's WITH statement also has one of the few mechanisms which can gracefully handle an error on releasing a resource. Exceptions in C++, Java, and Javascript are more troublesome.
[1] https://github.com/rust-lang/rfcs/blob/master/text/1236-stab...