Here's another link about the problems with C++ exception that I find very insightful https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p25... The major issue that stood out to me is that in a multi-threaded environment, exception unwinding is effectively single-threaded. This means that if you have C++ code that throws a lot of exceptions, you are going to see a lot of threads getting blocked by lock contenti…
to be clear, the single-threaded behaviour of some implementations is, well, implementation specific. There is nothing in the C++ standard that requires that. In particular, for GCC under linux, the issue is that the unwinder need to parse the unwind tables and needs to protect itself from a concurrent ldclose yanking them under it. There is some work currently on GCC to move this cost from unwinding to ldclose and a…
Avoid exception throwing in performance-sensitive code
161–170 of 243 posts
Re: Avoid exception throwing in performance-sensitive code
#162I remember programming in Ada in my undergrad years and using exceptions for control flow was a common idiom. It was only later and in other languages that exceptions were treated purely as error conditions. Using exceptions allows you to separate corner cases from the normal logic. This was very clean -- not ugly as the author infers. His example is ugly, but is a straw man example.
Re: Avoid exception throwing in performance-sensitive code
#163Earlier quoted context omitted.
to be clear, the single-threaded behaviour of some implementations is, well, implementation specific. There is nothing in the C++ standard that requires that. In particular, for GCC under linux, the issue is that the unwinder need to parse the unwind tables and needs to protect itself from a concurrent ldclose yanking them under it. There is some work currently on GCC to move this cost from unwinding to ldclose and a…
Sounds like a job for hazard pointers.
Re: Avoid exception throwing in performance-sensitive code
#164Earlier quoted context omitted.
"Exceptions should be... the exception." :)
The problem is exceptions have entirely opaque flow control. They're the opposite of a goto statement: a comes-from statement if you will. Flow control could originate literally anywhere down the stack and that makes reasoning about what's happening very difficult. Depending on the language it can also have a super broad and ever-changing surface area.
Re: Avoid exception throwing in performance-sensitive code
#165Earlier quoted context omitted.
But there are a bunch of codes which are yet to be verified as exception-safe. And in the gaming industry it's often third party code that you cannot even inspect.
The right statement is then that it is very hard to retrofit exceptions in an non-exception safe code base. Exception safety itself is not easy, as it requires different code patterns and idioms than usual. I believe that those idioms are useful and great even for non-exceptional code, but that's another story.
Re: Avoid exception throwing in performance-sensitive code
#166Earlier quoted context omitted.
Exception is a way to return from a function abnormally. So yes, they are for exceptional conditions. IMO it's perfectly fine to use them for input validation. The Java standard library itself does it all the time.
Java is the... uhm... exception here. That's not how idiomatic C++ is. Nor Rust. Nor Go. One of Java's (incl standard library) main design flaws is overuse of exceptions. It should not be emulated. It's too late to fix Java, but that doesn't make it a good idea.
Re: Avoid exception throwing in performance-sensitive code
#167Exceptions are starting to feel like a legacy programming paradigm to me. Rust & Go have, at least in a practical programming context, shown that errors-as-values has far less footguns and encourages better error handling practices than exceptions, which often are treated as an afterthought or end up being abused like in this post. Whenever I'm writing Python or Java I can't help but feel anxious about calling a func…
> Exceptions are starting to feel like a legacy programming paradigm to me. Rust & Go have, at least in a practical programming context, shown that errors-as-values has far less footguns They don't really. Because they force you to handle errors even in code that couldn't care less about errors because that's the responsibility of a higher level up the stack. And worse, they assume that an exception is a valid reason…
These are more practical (and good thing Rust isn't rigid at the expense of pragmatism).
And of course since panics are not the answer to everything exceptional, there's now a `catch_unwind`, too
Re: Avoid exception throwing in performance-sensitive code
#168Earlier quoted context omitted.
I think what Java got wrong was allowing catching unchecked exceptions. If Java had only allowed recovering from checked exceptions, it would have been a very similar experience to Rust's Result and panic. Instead, the trend was to avoid using checked exceptions at all, which perpetuated the crazy situation we're in where library code can suddenly abort and the author shrugs and says "shoulda read the docs".
> I think what Java got wrong was allowing catching unchecked exceptions. If Java had only allowed recovering from checked exceptions, it would have been a very similar experience to Rust's Result and panic. > Instead, the trend was to avoid using checked exceptions at all Java's type system was far too weak for that to be at all practical. Early Java not only didn't have first-class functions, it didn't even have ge…
It is possible, and straightforward, to do that if the set of checked exceptions is of a statically known size, and the wrapper function can propagate the exceptions rather than catch and rethrow them. In my experience, that is a very common situation (although not universal).
If you want to catch and rethrow, that can also be done, but it requires an evil hack, and the wrapper will need to take a reified type for the exception.
Re: Avoid exception throwing in performance-sensitive code
#169Earlier quoted context omitted.
Rust makes a distinction between recoverable and unrecoverable errors. Recoverable errors are the E in Result . You can take action and recover, depending on what kind of E it is. Unrecoverable errors are things like stack overflows or out of bounds array access. There is no reasonable way to soldier on after this, so the program should just end. Trying to continue the program in such situations only leads to pain. L…
> Unrecoverable errors are things like stack overflows or out of bounds array access. There is no reasonable way to soldier on after this, so the program should just end No, I wholeheartedly disagree with this. It's the equivalent of exit(1) some way down the stack. Whats recoverable or not depends on the use case and is a decision to be made by the caller of a function, not the implementor.
Otherwise I agree with you, that library code should not fail/crash/exit(1) just because of some judgement about recoverability, and out to clean up after itself before passing control back to the caller. If the user wants to fix some ENOSPC deep in my library by shelling out to "rm -rf /" and then trying again, that's fine by me, and this should be reflected in the API.
Re: Avoid exception throwing in performance-sensitive code
#170Earlier quoted context omitted.
At least for Go (haven't used Rust), I entirely disagree. After ~3 years of professional programming with the language, `if err != nil` is still constantly annoying me when writing code, but especially and most importantly, when reviewing code. Not to mention, Go has proven conclusively to me that exceptions are exactly the right pattern for error propagation - the 99.9% pattern is "function returns error with messag…
Absolutely. Even after "compressing" my code as much as possible, it looks as if 2/3 of a Go program is pure error handling and no business logic. I just don't understand this militant objection toward exceptions now. Even back in the days of slower virtual machines and crappier hardware, we were fine , and now it's code red! Get rid of exceptions! Performance! This is in an era of tech where everyone is building BAD…
This is exactly why it's good. It forces developers to think about things outside the happy path business logic. And it does this at the point where they know best what such an error could mean.
Proponents of exceptions let their users catch the exceptions they overlooked.
If you ask me Go is not forcing this enough, the ML style Result types in Rust are a much better abstraction here.