Live data from Hacker News

Current hardware trends make C++ exceptions harder to justify

open-std.org

311–320 of 516 posts

Re: Current hardware trends make C++ exceptions harder to justify

#311

Earlier quoted context omitted.

For AAA / high-performance / console / close-to-the-metal video games, at least. There are tons of games where exceptions are perfectly fine. Though still more often used for "probably going to crash soon" situations than otherwise, I'd wager.

Since exception handling in desktop runtime environments usually takes an unbounded amount of time, it’s not good practice to use them in your main loop since you have to guarantee a new frame at 60Hz. You can definitely do it but you’d be conceptually allowing for frame skips in your codebase. It could be difficult to audit and remove this assumption if down the road you wanted to tighten up your main loop code.

Agreed about main loop — that requires special care.

But there's often lots of other stuff going on, such as IO in other threads. You wouldn't want that stuff in your main loop for the same reasons, so since it's segregated anyway, exceptions aren't so bad (usually).

Re: Current hardware trends make C++ exceptions harder to justify

#312
post #191

I find this paper quite unconvincing. Exceptions are exceptional so in principle it doesn't matter (within reason) how long it takes to throw one as long as it costs nothing not to do so. So measuring the cost of repeated throws IMHO doesn't cast light on any useful case, and the approaches that add runtime cost for the path not taken, even Herb Sutter's, are not acceptable. His code transformation example is simply…

The only way exceptions should be exceptional is that they should rarely be used in any code base. At best, the are a micro optimization that helps you a tiny bit in the success case. They should be used when standard return value errors are measured to be impacting perf (ie. exceedingly rarely). Unfortunately, C++ language authors made them basically a requirement for OOP and RAII.

Imagine writing a parser. Can you use exceptions? It's hard to say! In fact, often impossible to say! How often an exception is thrown is highly dependent on the input data. If you're in a controlled environment with nearly always well formed data, it might be a perf win! But there's a ton of complexity in just deciding which type of error to use, and thats on top of the complexity of now having multiple ways of returning errors!

No one likes code that has 2+ ways of indicating method failure. If you are a library author, do your users need to check for both Exceptions and Error codes? If you are a nice author, you'll just choose 1 way to indicate failure and wrap where necessary.

If you want to use exceptions, they should be used in very limited scope when perf measurements indicate they would help, tightly wrapped in a catch, and then immediately converted to some other standard error type.

Even better, we should just let the choice of when to use exceptions up to an optimizing compiler, and provide the compiler a function to convert between exceptions and our more general purpose error type of choice.

Re: Current hardware trends make C++ exceptions harder to justify

#313
post #7

Earlier quoted context omitted.

I've been using `expected`, i.e. value-or-error type, for a while in C++ and it works just fine, but the article shows it has some noticeable overhead for the `fib` workload for instance. Not sure if the Rust implementation has a different design to make it perform better though.

> Not sure if the Rust implementation has a different design to make it perform better though. Prolly not, I expect the issue comes from the increase in branches since a value-based error reporting has to branch on every function return. Even if the branch is predictible, it’s not free. And fib() would be a worst-case scenario as it does very little per-call, the constant per-call overhead would be rather major.

It's also worth noting that Rust does also have stack-unwinding error propagation, in the form of `panic`/`catch_unwind`, which can be used as a less-ergonomic optimization in situations like this. Result types like this also don't color the function, since you can just explicitly panic, which would be inlined at the call site and show similar performance to C++ exceptions.

Re: Current hardware trends make C++ exceptions harder to justify

#314
post #170

Earlier quoted context omitted.

Java's checked exceptions are generally regarded as a mistake. There's a reason no other languages has them, and newer JVM languages (Groovy, Clojure, Scala, Kotlin) treat all exceptions as runtime. Anders Hejlsberg (creator of Delphi, C# and Typescript) also has an excellent article on their problems [1]. In modern Java I see nearly only runtime exceptions used, especially because that's necessary for most Java 8+ l…

" Java's checked exceptions are generally regarded as a mistake. " By people who do not want to believe that errors are part of a system's API and prefer to just write the happy path and let any exception kill the process. And who don't mind getting called at 2:00 am because a dependency buried deep in a subsystem threw an exception that you'd never heard of before.

> errors are part of a system's API

This is a really interesting and nuanced point here. The article linked above [1] talks a bit about it. The problem is, they both are and aren't part of the API in the strict sense.

In the sense that they specify a contractual behaviour they are part of the API of a function. But in the sense that they are something the caller should / needs to specifically care about, they sit in between. That is, in the vast majority of cases, the caller does not care specifically what exception occurred. Generally they want to clean up resources and pass the error up the chain. It is "exceptional" that a caller will react in a specific way to to a specific type of exception. So this is where Java goes wrong because it forces the fine grained exception handling into the client when the majority case (and preferred case generally) is the opposite. It makes you treat the minority case as the main case. There are ways to work around / deal with this but nearly all of them are bad. The article talks about some of the badness.

I do think it's interesting though that Rust has taken off and is generally admired for a very similar type of feature (compiler enforced memory safety). I am really curious how that will age, but so far it seems like it is holding up.

[1] https://www.artima.com/articles/the-trouble-with-checked-exc...

Re: Current hardware trends make C++ exceptions harder to justify

#315

Earlier quoted context omitted.

You also have to abandon operator new and STL unless you want to pretend they never fail.

Right, I use an allocator that just aborts. Imagining your program can recover from alloc failures has always struck me as fanciful, or at least out of the realm of my experience.

It's a legitimate thing in embedded and other memory-constrained circumstances, when you have something like a large cache and an allocation failure can trigger manual pruning or GC.

Re: Current hardware trends make C++ exceptions harder to justify

#316
post #262

Earlier quoted context omitted.

When something happens that violates your assumptions about your own program's behavior, throwing it into a state where it doesn't know what happens next. Kind of like a panic.

This would mean that attempting to open a file that doesn't exist shouldn't throw an exception. But that is exactly what it does in the standard libraries of many languages with exceptions.

It should be up to the application to throw or not, not a library. I write a system service. If it can't find the configuration file, it can't continue, so it throws an exception. If it can't open a file that contains state from a previous run (maybe because it's the first time it's running) that's fine, the program can run without it and thus, no exception.

Re: Current hardware trends make C++ exceptions harder to justify

#317
It's unclear to me if the author is saying that the global mutex for unwinding the stack interferes with the non-exception-throwing code paths, or are they just saying that the exceptions themselves bottleneck and are so inefficient that this becomes a significant impact on overall throughput?

It does seem like at least in theory it should be possible to create a non-locking / blocking exception unwinder, if there is no actual contention between the threads. If that can be done then it seems like the solution should be to do that rather than abandon a whole language feature. This is a bit like the Python GIL question. I would say if the language spec means you have to have a "GIL" in any context in a high performance language like C++ then it ought to be addressed at the spec level.

Re: Current hardware trends make C++ exceptions harder to justify

#318
post #191

I find this paper quite unconvincing. Exceptions are exceptional so in principle it doesn't matter (within reason) how long it takes to throw one as long as it costs nothing not to do so. So measuring the cost of repeated throws IMHO doesn't cast light on any useful case, and the approaches that add runtime cost for the path not taken, even Herb Sutter's, are not acceptable. His code transformation example is simply…

I'm certainly not an expert but as far as I understand, fixing the exception global lock need not break the ABI on gcc/glibc. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71744

Turns out I need to read more carefully. Improvements can be done in a non-abi breaking way, but more radical changes are, according to the authors ABI breaking.

Re: Current hardware trends make C++ exceptions harder to justify

#319

Earlier quoted context omitted.

That argument is only true in single threaded applications, at least given today's exception implementations. The more threads you have, the more problematic exceptions become. On the large machine you start to see performance problems with 0.1% failure rate, which is not that much. An core counts continue to rise.

Again, most experienced C++ programmers would say that even a 0.1% "normal" failure rate indicates a situation that should not be handled by exceptions. You seem to be describing a style of programming where there's a bunch of work to be done, most efforts to do the work will succeed, a few will predictably (albeit randomly, perhaps) fail. While I would concede that you might conclude that exceptions are the perfect…

If our system (algo trading) throws an exception, we collect core dumps from all threads, error messages go to all of our dashboards, and the system waits for a graceful restart. Exceptions almost always are due to something that should NEVER happen, and we will push out a fix ASAP. It is "exceptional" because we expect the call rate to be 0.00000%.

I keep reading how terrible exceptions are, and the examples are almost always in hot inner loops. If a junior dev put this code in a PR (a senior dev should NOT be doing this), we would require them to fix it.

Re: Current hardware trends make C++ exceptions harder to justify

#320
post #308
post #297

Earlier quoted context omitted.

I thought you could tune away the trace on creation behavior. Regardless, I'd be interested in seeing if this is a performance bottleneck. I'd guess it is only relevant on dataset processing. Closer you are to a place that legitimately can toss to a user, more likely you are to not care? That is, if the common case of an exception is to stop and ask for intervention, is this a concern at all?

> I thought you could tune away the trace on creation behavior. You can when you implement your own exception type, but not in general (and doing so would break too many things). Exceptions are thrown and caught quite frequently in Java for "expected" cases, for example when attempting to parse a number from a string which is not a valid number. It's generally not a performance problem, and stack trace collection is…

Quickly googling, I see the is an option for implicit exceptions to omit stack frame for fast throw. Seems finicky, though.

But, yes, I realize most of these are probably not noticable.

Post reply on HN